Message ID | 1395951605-3931-2-git-send-email-santosh.shukla@linaro.org |
---|---|
State | Superseded |
Headers | show |
On 2014-03-27 13:20, Santosh Shukla wrote: > From: santosh shukla <santosh.shukla@linaro.org> > > Application open PF_INET socket, spawns two thread, > one is sender_ping_thr another one listen_thr. > Each send request arms timer for absolute timeout duration > Whenever listner thread recieves ack, it cancels the timer_out > and free the timeout buffer i.e. tmo_buf allocate while arming.. > Otherwise timeout-event-notfier will enqueue time out even to > queue for that pckt_cnt. > > Signed-off-by: santosh shukla <santosh.shukla@linaro.org> > --- > V2 change : > - incorporated style comment in patch > - odp queue based socket api need more changes specific > to flag setting like socket flag, socket type, parameterising setsockopt > this program need flags i.e..SOL_IP, IP_TTL etc,, > At this point my initial effort says it will take little more time > to get other parameter support in pktio socket param in odp > therefore I suggest that this could be todo and seubsequent patch > to include qeueue-base-socket method as and when I manage solve > socket parameter problem for this application. > > test/api_test/Makefile | 16 +- > test/api_test/odp_common.h | 1 + > test/api_test/odp_timer_ping.c | 332 ++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 347 insertions(+), 2 deletions(-) > create mode 100644 test/api_test/odp_timer_ping.c > > diff --git a/test/api_test/Makefile b/test/api_test/Makefile > index bd99c50..0398cd2 100644 > --- a/test/api_test/Makefile > +++ b/test/api_test/Makefile > @@ -11,6 +11,7 @@ ODP_ROOT = ../.. > ODP_ATOMIC = odp_atomic > ODP_SHM = odp_shm > ODP_RING = odp_ring > +ODP_TIM = odp_timer > > include $(ODP_ROOT)/Makefile.inc > include ../Makefile.inc > @@ -32,13 +33,18 @@ RING_OBJS = > RING_OBJS += $(OBJ_DIR)/odp_common.o > RING_OBJS += $(OBJ_DIR)/odp_ring_test.o > > -DEPS = $(ATOMIC_OBJS:.o=.d) $(SHM_OBJS:.o=.d) $(RING_OBJS:.o=.d) > +TIM_OBJS = > +TIM_OBJS += $(OBJ_DIR)/odp_common.o > +TIM_OBJS += $(OBJ_DIR)/odp_timer_ping.o > + > +DEPS = $(ATOMIC_OBJS:.o=.d) $(SHM_OBJS:.o=.d) $(RING_OBJS:.o=.d) $(TIM_OBJS:.o=.d) > > .PHONY: all > -all: $(OBJ_DIR) $(ODP_ATOMIC) $(ODP_SHM) $(ODP_RING) > +all: $(OBJ_DIR) $(ODP_ATOMIC) $(ODP_SHM) $(ODP_RING) $(ODP_TIM) > atomic: $(OBJ_DIR) $(ODP_ATOMIC) > shm: $(OBJ_DIR) $(ODP_SHM) > ring: $(OBJ_DIR) $(ODP_RING) > +timer: $(OBJ_DIR) $(ODP_TIM) > > -include $(DEPS) > > @@ -64,12 +70,17 @@ $(ODP_RING): $(ODP_LIB) $(RING_OBJS) > $(ECHO) Linking $< > $(CC) $(LDFLAGS) $(RING_OBJS) $(ODP_LIB) $(STD_LIBS) -o $@ > > +$(ODP_TIM): $(ODP_LIB) $(TIM_OBJS) > + $(ECHO) Linking $< > + $(CC) $(LDFLAGS) $(TIM_OBJS) $(ODP_LIB) $(STD_LIBS) -o $@ > + > .PHONY: clean > clean: > $(RMDIR) $(OBJ_DIR) > $(RM) $(ODP_ATOMIC) > $(RM) $(ODP_SHM) > $(RM) $(ODP_RING) > + $(RM) $(ODP_TIM) > $(MAKE) -C $(ODP_DIR) clean > > .PHONY: install > @@ -78,3 +89,4 @@ install: > install -m 0755 $(ODP_ATOMIC) $(DESTDIR)/share/odp/ > install -m 0755 $(ODP_SHM) $(DESTDIR)/share/odp/ > install -m 0755 $(ODP_RING) $(DESTDIR)/share/odp/ > + install -m 0755 $(ODP_TIM) $(DESTDIR)/share/odp/ > diff --git a/test/api_test/odp_common.h b/test/api_test/odp_common.h > index e8201ac..f5183e1 100644 > --- a/test/api_test/odp_common.h > +++ b/test/api_test/odp_common.h > @@ -20,6 +20,7 @@ typedef enum { > ODP_SHM_TEST, > ODP_RING_TEST_BASIC, > ODP_RING_TEST_STRESS, > + ODP_TIMER_PING_TEST, > ODP_MAX_TEST > } odp_test_case_e; > > diff --git a/test/api_test/odp_timer_ping.c b/test/api_test/odp_timer_ping.c > new file mode 100644 > index 0000000..df56072 > --- /dev/null > +++ b/test/api_test/odp_timer_ping.c > @@ -0,0 +1,332 @@ > +/* Copyright (c) 2014, Linaro Limited > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > + > +/** > + * @file > + * > + * ODP timer ping example application. > + * application open PF_INET socket, every ping send request > + * will arm timer for some duration, if ping_ack rxvd with > + * time band.. listen thread will cancel timer and free the > + * tmo_buffer.. otherwise timer expiration event will exit > + * application lead to test failure.. > + * - two thread used, one listener other one sender. > + * - run ./odp_timer <ipadder> > + * In ubuntu, you need run using sudo ./odp_timer <ipaddr> > + * - so to tigger timeout explicitly.. ping with badipaddr > + * Otherwise timeout may happen bcz of slow nw speed > + */ > + > + > +#include <unistd.h> > +#include <fcntl.h> > +#include <errno.h> > +#include <sys/socket.h> > +#include <resolv.h> > +#include <netdb.h> > +#include <netinet/in.h> > +#include <netinet/ip_icmp.h> > +#include <arpa/inet.h> > + > +#include <string.h> > +#include <odp.h> > +#include <odp_common.h> > +#include <odp_timer.h> > +#include <helper/odp_chksum.h> > + > +#define MSG_POOL_SIZE (4*1024*1024) > +#define BUF_SIZE 8 > +#define PING_CNT 10 > + > + > +static odp_timer_t test_timer_ping; > +static odp_timer_tmo_t test_ping_tmo; > + > +#define PKTSIZE 64 > +struct packet { > + struct icmphdr hdr; > + char msg[PKTSIZE-sizeof(struct icmphdr)]; > +}; > + > +int pid = -1; > +struct protoent *proto; > + > +struct sockaddr_in dst_addr; > + > +/* local struct for ping_timer_thread argument */ > +typedef struct { > + pthrd_arg thrdarg; > + int result; > +} ping_arg_t; > + > +static int ping_sync_flag; > + > + > +static void dump_icmp_pkt(void *buf, int bytes, int pkt_cnt) > +{ > + int i; > + struct iphdr *ip = buf; > + > + ODP_DBG("---dump icmp pkt_cnt %d------\n", pkt_cnt); > + for (i = 0; i < bytes; i++) { > + if (!(i & 15)) > + ODP_DBG("\n %x: ", i); > + ODP_DBG("%d ", ((unsigned char *)buf)[i]); > + } > + ODP_DBG("\n"); > + char addrstr[INET6_ADDRSTRLEN]; > + inet_ntop(AF_INET, &ip->daddr, addrstr, sizeof(addrstr)); > + ODP_DBG("byte %d, Ack rxvd for msg_cnt [%d] from %s\n", bytes, pkt_cnt, addrstr); > +} > + > + > +static int listen_to_pingack(void) > +{ > + int sd, i; > + struct sockaddr_in addr; > + unsigned char buf[1024]; > + int bytes, len; > + > + sd = socket(PF_INET, SOCK_RAW, proto->p_proto); > + if (sd < 0) { > + ODP_ERR("Listener socket open failed\n"); > + return -1; > + } > + > + for (i = 0; i < PING_CNT; i++) { > + len = sizeof(addr); > + > + bzero(buf, sizeof(buf)); > + bytes = recvfrom(sd, buf, sizeof(buf), 0, > + (struct sockaddr *)&addr, > + (socklen_t *)&len); > + if (bytes > 0) { > + /* pkt rxvd therefore cancel the timeout */ > + if (odp_timer_cancel_tmo(test_timer_ping, > + test_ping_tmo) != 0) { > + ODP_ERR("cancel_tmo failed ..exiting listner thread\n"); > + return -1; > + } > + > + /* cruel bad hack used for sender, listner ipc.. > + * euwww.. FIXME .. > + */ > + ping_sync_flag = true; > + dump_icmp_pkt(buf, bytes, i); > + } else { > + ODP_ERR("recvfrom operation failed for msg_cnt [%d]\n", i); > + return -1; > + } > + } > + > + return 0; > +} > + > + > +static int send_ping_request(struct sockaddr_in *addr) > +{ > + const int val = 255; > + uint32_t i, j; > + int sd, cnt = 1; > + struct packet pckt; > + > + uint64_t tick; > + odp_queue_t queue; > + odp_buffer_t buf; > + > + int thr; > + thr = odp_thread_id(); > + > + sd = socket(PF_INET, SOCK_RAW, proto->p_proto); > + if (sd < 0) { > + ODP_ERR("Sender socket open failed\n"); > + return -1; > + } > + > + if (setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)) != 0) { > + ODP_ERR("Error setting TTL option\n"); > + return -1; > + } > + if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0) { > + ODP_ERR("Request for nonblocking I/O failed\n"); > + return -1; > + } > + > + /* get the ping queue */ > + queue = odp_queue_lookup("ping_timer_queue"); > + > + for (i = 0; i < PING_CNT; i++) { > + /* prepare icmp pkt */ > + bzero(&pckt, sizeof(pckt)); > + pckt.hdr.type = ICMP_ECHO; > + pckt.hdr.un.echo.id = pid; > + > + for (j = 0; j < sizeof(pckt.msg)-1; j++) > + pckt.msg[j] = j+'0'; > + > + pckt.msg[j] = 0; > + pckt.hdr.un.echo.sequence = cnt++; > + pckt.hdr.checksum = odp_chksum(&pckt, sizeof(pckt)); > + > + > + /* txmit the pkt */ > + if (sendto(sd, &pckt, sizeof(pckt), 0, > + (struct sockaddr *)addr, sizeof(*addr)) <= 0) { > + ODP_ERR("sendto operation failed msg_cnt [%d]..exiting sender thread\n", i); > + return -1; > + } > + printf(" icmp_sent msg_cnt %d\n", i); > + > + /* arm the timer */ > + tick = odp_timer_current_tick(test_timer_ping); > + ODP_DBG(" [%i] current tick %"PRIu64"\n", thr, tick); > + > + tick += 1000; > + test_ping_tmo = odp_timer_absolute_tmo(test_timer_ping, tick, > + queue, > + ODP_BUFFER_INVALID); > + > + /* wait for timeout event */ > + while ((buf = odp_queue_deq(queue) == ODP_BUFFER_INVALID)) { > + /* flag true means ack rxvd.. a cruel hack as I > + * am confused on method to get away from while > + * loop in case of ack rxvd.. > + * FIXME.. > + */ > + if (ping_sync_flag) { > + ping_sync_flag = false; > + ODP_DBG(" [%d] done :)!!\n", i); > + buf = ODP_BUFFER_INVALID; > + break; > + } > + } > + > + /* free tmo_buf for timeout case */ > + if (buf != ODP_BUFFER_INVALID) { > + ODP_DBG(" [%i] timeout msg_cnt [%i] (:-\n", thr, i); > + odp_buffer_free(buf); > + } > + } > + > + return 0; > +} > + > + > +static void *ping_timer_thread(void *arg) > +{ > + ping_arg_t *parg = (ping_arg_t *)arg; > + int thr; > + > + thr = odp_thread_id(); > + > + printf("Ping thread %i starts\n", thr); > + > + switch (parg->thrdarg.testcase) { > + case ODP_TIMER_PING_TEST: > + if (thr == 1) > + if (send_ping_request(&dst_addr) < 0) > + parg->result = -1; > + if (thr == 2) > + if (listen_to_pingack() < 0) > + parg->result = -1; > + break; > + default: > + ODP_ERR("Invalid test case [%d]\n", parg->thrdarg.testcase); > + } > + > + > + fflush(stdout); > + > + return parg; > +} > + > +static int ping_init(int count, char *name[]) > +{ > + struct hostent *hname; > + if (count != 2) { > + ODP_ERR("usage: %s <hostaddr>\n", name[0]); > + return -1; > + } > + > + if (count > 1) { > + pid = getpid(); > + proto = getprotobyname("ICMP"); > + hname = gethostbyname(name[1]); > + bzero(&dst_addr, sizeof(dst_addr)); > + dst_addr.sin_family = hname->h_addrtype; > + dst_addr.sin_port = 0; > + dst_addr.sin_addr.s_addr = *(long *)hname->h_addr; > + } > + printf("ping to addr %s\n", name[1]); > + > + return 0; > +} > + > + > +int main(int argc ODP_UNUSED, char *argv[] ODP_UNUSED) > +{ > + ping_arg_t pingarg; > + odp_queue_t queue; > + odp_buffer_pool_t pool; > + void *pool_base; > + > + if (odp_test_global_init() != 0) > + return -1; > + > + odp_print_system_info(); > + > + if (ping_init(argc, argv) != 0) > + return -1; > + > + /* > + * Create message pool > + */ > + pool_base = odp_shm_reserve("msg_pool", > + MSG_POOL_SIZE, ODP_CACHE_LINE_SIZE); > + > + pool = odp_buffer_pool_create("msg_pool", pool_base, MSG_POOL_SIZE, > + BUF_SIZE, > + ODP_CACHE_LINE_SIZE, > + ODP_BUFFER_TYPE_RAW); > + if (pool == ODP_BUFFER_POOL_INVALID) { > + ODP_ERR("Pool create failed.\n"); > + return -1; > + } > + > + /* > + * Create a queue for timer test > + */ > + queue = odp_queue_create("ping_timer_queue", ODP_QUEUE_TYPE_SCHED, > + NULL); > + > + if (queue == ODP_QUEUE_INVALID) { > + ODP_ERR("Timer queue create failed.\n"); > + return -1; > + } > + > + test_timer_ping = odp_timer_create("ping_timer", pool, > + 1000000, 1000000, 1000000000000); > + odp_shm_print_all(); > + > + pingarg.thrdarg.testcase = ODP_TIMER_PING_TEST; > + pingarg.thrdarg.numthrds = odp_sys_core_count(); > + > + pingarg.result = 0; > + > + /* Create and launch worker threads */ > + odp_test_thread_create(ping_timer_thread, (pthrd_arg *)&pingarg); > + > + /* Wait for worker threads to exit */ > + odp_test_thread_exit(&pingarg.thrdarg); > + > + ODP_DBG("ping timer test %s\n", (pingarg.result == 0) ? "passed" : "failed"); > + > + printf("ODP ping timer test complete\n\n"); > + > + return 0; > +} > + > -- > 1.7.9.5 > to start with: Applying: timer:ping test application /home/anders/src/odp/.git/rebase-apply/patch:424: new blank line at EOF. + warning: 1 line adds whitespace errors.
On 28 March 2014 02:51, Anders Roxell <anders.roxell@linaro.org> wrote: > On 2014-03-27 13:20, Santosh Shukla wrote: >> From: santosh shukla <santosh.shukla@linaro.org> >> >> Application open PF_INET socket, spawns two thread, >> one is sender_ping_thr another one listen_thr. >> Each send request arms timer for absolute timeout duration >> Whenever listner thread recieves ack, it cancels the timer_out >> and free the timeout buffer i.e. tmo_buf allocate while arming.. >> Otherwise timeout-event-notfier will enqueue time out even to >> queue for that pckt_cnt. >> >> Signed-off-by: santosh shukla <santosh.shukla@linaro.org> >> --- >> V2 change : >> - incorporated style comment in patch >> - odp queue based socket api need more changes specific >> to flag setting like socket flag, socket type, parameterising setsockopt >> this program need flags i.e..SOL_IP, IP_TTL etc,, >> At this point my initial effort says it will take little more time >> to get other parameter support in pktio socket param in odp >> therefore I suggest that this could be todo and seubsequent patch >> to include qeueue-base-socket method as and when I manage solve >> socket parameter problem for this application. >> >> test/api_test/Makefile | 16 +- >> test/api_test/odp_common.h | 1 + >> test/api_test/odp_timer_ping.c | 332 ++++++++++++++++++++++++++++++++++++++++ >> 3 files changed, 347 insertions(+), 2 deletions(-) >> create mode 100644 test/api_test/odp_timer_ping.c >> >> diff --git a/test/api_test/Makefile b/test/api_test/Makefile >> index bd99c50..0398cd2 100644 >> --- a/test/api_test/Makefile >> +++ b/test/api_test/Makefile >> @@ -11,6 +11,7 @@ ODP_ROOT = ../.. >> ODP_ATOMIC = odp_atomic >> ODP_SHM = odp_shm >> ODP_RING = odp_ring >> +ODP_TIM = odp_timer >> >> include $(ODP_ROOT)/Makefile.inc >> include ../Makefile.inc >> @@ -32,13 +33,18 @@ RING_OBJS = >> RING_OBJS += $(OBJ_DIR)/odp_common.o >> RING_OBJS += $(OBJ_DIR)/odp_ring_test.o >> >> -DEPS = $(ATOMIC_OBJS:.o=.d) $(SHM_OBJS:.o=.d) $(RING_OBJS:.o=.d) >> +TIM_OBJS = >> +TIM_OBJS += $(OBJ_DIR)/odp_common.o >> +TIM_OBJS += $(OBJ_DIR)/odp_timer_ping.o >> + >> +DEPS = $(ATOMIC_OBJS:.o=.d) $(SHM_OBJS:.o=.d) $(RING_OBJS:.o=.d) $(TIM_OBJS:.o=.d) >> >> .PHONY: all >> -all: $(OBJ_DIR) $(ODP_ATOMIC) $(ODP_SHM) $(ODP_RING) >> +all: $(OBJ_DIR) $(ODP_ATOMIC) $(ODP_SHM) $(ODP_RING) $(ODP_TIM) >> atomic: $(OBJ_DIR) $(ODP_ATOMIC) >> shm: $(OBJ_DIR) $(ODP_SHM) >> ring: $(OBJ_DIR) $(ODP_RING) >> +timer: $(OBJ_DIR) $(ODP_TIM) >> >> -include $(DEPS) >> >> @@ -64,12 +70,17 @@ $(ODP_RING): $(ODP_LIB) $(RING_OBJS) >> $(ECHO) Linking $< >> $(CC) $(LDFLAGS) $(RING_OBJS) $(ODP_LIB) $(STD_LIBS) -o $@ >> >> +$(ODP_TIM): $(ODP_LIB) $(TIM_OBJS) >> + $(ECHO) Linking $< >> + $(CC) $(LDFLAGS) $(TIM_OBJS) $(ODP_LIB) $(STD_LIBS) -o $@ >> + >> .PHONY: clean >> clean: >> $(RMDIR) $(OBJ_DIR) >> $(RM) $(ODP_ATOMIC) >> $(RM) $(ODP_SHM) >> $(RM) $(ODP_RING) >> + $(RM) $(ODP_TIM) >> $(MAKE) -C $(ODP_DIR) clean >> >> .PHONY: install >> @@ -78,3 +89,4 @@ install: >> install -m 0755 $(ODP_ATOMIC) $(DESTDIR)/share/odp/ >> install -m 0755 $(ODP_SHM) $(DESTDIR)/share/odp/ >> install -m 0755 $(ODP_RING) $(DESTDIR)/share/odp/ >> + install -m 0755 $(ODP_TIM) $(DESTDIR)/share/odp/ >> diff --git a/test/api_test/odp_common.h b/test/api_test/odp_common.h >> index e8201ac..f5183e1 100644 >> --- a/test/api_test/odp_common.h >> +++ b/test/api_test/odp_common.h >> @@ -20,6 +20,7 @@ typedef enum { >> ODP_SHM_TEST, >> ODP_RING_TEST_BASIC, >> ODP_RING_TEST_STRESS, >> + ODP_TIMER_PING_TEST, >> ODP_MAX_TEST >> } odp_test_case_e; >> >> diff --git a/test/api_test/odp_timer_ping.c b/test/api_test/odp_timer_ping.c >> new file mode 100644 >> index 0000000..df56072 >> --- /dev/null >> +++ b/test/api_test/odp_timer_ping.c >> @@ -0,0 +1,332 @@ >> +/* Copyright (c) 2014, Linaro Limited >> + * All rights reserved. >> + * >> + * SPDX-License-Identifier: BSD-3-Clause >> + */ >> + >> + >> +/** >> + * @file >> + * >> + * ODP timer ping example application. >> + * application open PF_INET socket, every ping send request >> + * will arm timer for some duration, if ping_ack rxvd with >> + * time band.. listen thread will cancel timer and free the >> + * tmo_buffer.. otherwise timer expiration event will exit >> + * application lead to test failure.. >> + * - two thread used, one listener other one sender. >> + * - run ./odp_timer <ipadder> >> + * In ubuntu, you need run using sudo ./odp_timer <ipaddr> >> + * - so to tigger timeout explicitly.. ping with badipaddr >> + * Otherwise timeout may happen bcz of slow nw speed >> + */ >> + >> + >> +#include <unistd.h> >> +#include <fcntl.h> >> +#include <errno.h> >> +#include <sys/socket.h> >> +#include <resolv.h> >> +#include <netdb.h> >> +#include <netinet/in.h> >> +#include <netinet/ip_icmp.h> >> +#include <arpa/inet.h> >> + >> +#include <string.h> >> +#include <odp.h> >> +#include <odp_common.h> >> +#include <odp_timer.h> >> +#include <helper/odp_chksum.h> >> + >> +#define MSG_POOL_SIZE (4*1024*1024) >> +#define BUF_SIZE 8 >> +#define PING_CNT 10 >> + >> + >> +static odp_timer_t test_timer_ping; >> +static odp_timer_tmo_t test_ping_tmo; >> + >> +#define PKTSIZE 64 >> +struct packet { >> + struct icmphdr hdr; >> + char msg[PKTSIZE-sizeof(struct icmphdr)]; >> +}; >> + >> +int pid = -1; >> +struct protoent *proto; >> + >> +struct sockaddr_in dst_addr; >> + >> +/* local struct for ping_timer_thread argument */ >> +typedef struct { >> + pthrd_arg thrdarg; >> + int result; >> +} ping_arg_t; >> + >> +static int ping_sync_flag; >> + >> + >> +static void dump_icmp_pkt(void *buf, int bytes, int pkt_cnt) >> +{ >> + int i; >> + struct iphdr *ip = buf; >> + >> + ODP_DBG("---dump icmp pkt_cnt %d------\n", pkt_cnt); >> + for (i = 0; i < bytes; i++) { >> + if (!(i & 15)) >> + ODP_DBG("\n %x: ", i); >> + ODP_DBG("%d ", ((unsigned char *)buf)[i]); >> + } >> + ODP_DBG("\n"); >> + char addrstr[INET6_ADDRSTRLEN]; >> + inet_ntop(AF_INET, &ip->daddr, addrstr, sizeof(addrstr)); >> + ODP_DBG("byte %d, Ack rxvd for msg_cnt [%d] from %s\n", bytes, pkt_cnt, addrstr); >> +} >> + >> + >> +static int listen_to_pingack(void) >> +{ >> + int sd, i; >> + struct sockaddr_in addr; >> + unsigned char buf[1024]; >> + int bytes, len; >> + >> + sd = socket(PF_INET, SOCK_RAW, proto->p_proto); >> + if (sd < 0) { >> + ODP_ERR("Listener socket open failed\n"); >> + return -1; >> + } >> + >> + for (i = 0; i < PING_CNT; i++) { >> + len = sizeof(addr); >> + >> + bzero(buf, sizeof(buf)); >> + bytes = recvfrom(sd, buf, sizeof(buf), 0, >> + (struct sockaddr *)&addr, >> + (socklen_t *)&len); >> + if (bytes > 0) { >> + /* pkt rxvd therefore cancel the timeout */ >> + if (odp_timer_cancel_tmo(test_timer_ping, >> + test_ping_tmo) != 0) { >> + ODP_ERR("cancel_tmo failed ..exiting listner thread\n"); >> + return -1; >> + } >> + >> + /* cruel bad hack used for sender, listner ipc.. >> + * euwww.. FIXME .. >> + */ >> + ping_sync_flag = true; >> + dump_icmp_pkt(buf, bytes, i); >> + } else { >> + ODP_ERR("recvfrom operation failed for msg_cnt [%d]\n", i); >> + return -1; >> + } >> + } >> + >> + return 0; >> +} >> + >> + >> +static int send_ping_request(struct sockaddr_in *addr) >> +{ >> + const int val = 255; >> + uint32_t i, j; >> + int sd, cnt = 1; >> + struct packet pckt; >> + >> + uint64_t tick; >> + odp_queue_t queue; >> + odp_buffer_t buf; >> + >> + int thr; >> + thr = odp_thread_id(); >> + >> + sd = socket(PF_INET, SOCK_RAW, proto->p_proto); >> + if (sd < 0) { >> + ODP_ERR("Sender socket open failed\n"); >> + return -1; >> + } >> + >> + if (setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)) != 0) { >> + ODP_ERR("Error setting TTL option\n"); >> + return -1; >> + } >> + if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0) { >> + ODP_ERR("Request for nonblocking I/O failed\n"); >> + return -1; >> + } >> + >> + /* get the ping queue */ >> + queue = odp_queue_lookup("ping_timer_queue"); >> + >> + for (i = 0; i < PING_CNT; i++) { >> + /* prepare icmp pkt */ >> + bzero(&pckt, sizeof(pckt)); >> + pckt.hdr.type = ICMP_ECHO; >> + pckt.hdr.un.echo.id = pid; >> + >> + for (j = 0; j < sizeof(pckt.msg)-1; j++) >> + pckt.msg[j] = j+'0'; >> + >> + pckt.msg[j] = 0; >> + pckt.hdr.un.echo.sequence = cnt++; >> + pckt.hdr.checksum = odp_chksum(&pckt, sizeof(pckt)); >> + >> + >> + /* txmit the pkt */ >> + if (sendto(sd, &pckt, sizeof(pckt), 0, >> + (struct sockaddr *)addr, sizeof(*addr)) <= 0) { >> + ODP_ERR("sendto operation failed msg_cnt [%d]..exiting sender thread\n", i); >> + return -1; >> + } >> + printf(" icmp_sent msg_cnt %d\n", i); >> + >> + /* arm the timer */ >> + tick = odp_timer_current_tick(test_timer_ping); >> + ODP_DBG(" [%i] current tick %"PRIu64"\n", thr, tick); >> + >> + tick += 1000; >> + test_ping_tmo = odp_timer_absolute_tmo(test_timer_ping, tick, >> + queue, >> + ODP_BUFFER_INVALID); >> + >> + /* wait for timeout event */ >> + while ((buf = odp_queue_deq(queue) == ODP_BUFFER_INVALID)) { >> + /* flag true means ack rxvd.. a cruel hack as I >> + * am confused on method to get away from while >> + * loop in case of ack rxvd.. >> + * FIXME.. >> + */ >> + if (ping_sync_flag) { >> + ping_sync_flag = false; >> + ODP_DBG(" [%d] done :)!!\n", i); >> + buf = ODP_BUFFER_INVALID; >> + break; >> + } >> + } >> + >> + /* free tmo_buf for timeout case */ >> + if (buf != ODP_BUFFER_INVALID) { >> + ODP_DBG(" [%i] timeout msg_cnt [%i] (:-\n", thr, i); >> + odp_buffer_free(buf); >> + } >> + } >> + >> + return 0; >> +} >> + >> + >> +static void *ping_timer_thread(void *arg) >> +{ >> + ping_arg_t *parg = (ping_arg_t *)arg; >> + int thr; >> + >> + thr = odp_thread_id(); >> + >> + printf("Ping thread %i starts\n", thr); >> + >> + switch (parg->thrdarg.testcase) { >> + case ODP_TIMER_PING_TEST: >> + if (thr == 1) >> + if (send_ping_request(&dst_addr) < 0) >> + parg->result = -1; >> + if (thr == 2) >> + if (listen_to_pingack() < 0) >> + parg->result = -1; >> + break; >> + default: >> + ODP_ERR("Invalid test case [%d]\n", parg->thrdarg.testcase); >> + } >> + >> + >> + fflush(stdout); >> + >> + return parg; >> +} >> + >> +static int ping_init(int count, char *name[]) >> +{ >> + struct hostent *hname; >> + if (count != 2) { >> + ODP_ERR("usage: %s <hostaddr>\n", name[0]); >> + return -1; >> + } >> + >> + if (count > 1) { >> + pid = getpid(); >> + proto = getprotobyname("ICMP"); >> + hname = gethostbyname(name[1]); >> + bzero(&dst_addr, sizeof(dst_addr)); >> + dst_addr.sin_family = hname->h_addrtype; >> + dst_addr.sin_port = 0; >> + dst_addr.sin_addr.s_addr = *(long *)hname->h_addr; >> + } >> + printf("ping to addr %s\n", name[1]); >> + >> + return 0; >> +} >> + >> + >> +int main(int argc ODP_UNUSED, char *argv[] ODP_UNUSED) >> +{ >> + ping_arg_t pingarg; >> + odp_queue_t queue; >> + odp_buffer_pool_t pool; >> + void *pool_base; >> + >> + if (odp_test_global_init() != 0) >> + return -1; >> + >> + odp_print_system_info(); >> + >> + if (ping_init(argc, argv) != 0) >> + return -1; >> + >> + /* >> + * Create message pool >> + */ >> + pool_base = odp_shm_reserve("msg_pool", >> + MSG_POOL_SIZE, ODP_CACHE_LINE_SIZE); >> + >> + pool = odp_buffer_pool_create("msg_pool", pool_base, MSG_POOL_SIZE, >> + BUF_SIZE, >> + ODP_CACHE_LINE_SIZE, >> + ODP_BUFFER_TYPE_RAW); >> + if (pool == ODP_BUFFER_POOL_INVALID) { >> + ODP_ERR("Pool create failed.\n"); >> + return -1; >> + } >> + >> + /* >> + * Create a queue for timer test >> + */ >> + queue = odp_queue_create("ping_timer_queue", ODP_QUEUE_TYPE_SCHED, >> + NULL); >> + >> + if (queue == ODP_QUEUE_INVALID) { >> + ODP_ERR("Timer queue create failed.\n"); >> + return -1; >> + } >> + >> + test_timer_ping = odp_timer_create("ping_timer", pool, >> + 1000000, 1000000, 1000000000000); >> + odp_shm_print_all(); >> + >> + pingarg.thrdarg.testcase = ODP_TIMER_PING_TEST; >> + pingarg.thrdarg.numthrds = odp_sys_core_count(); >> + >> + pingarg.result = 0; >> + >> + /* Create and launch worker threads */ >> + odp_test_thread_create(ping_timer_thread, (pthrd_arg *)&pingarg); >> + >> + /* Wait for worker threads to exit */ >> + odp_test_thread_exit(&pingarg.thrdarg); >> + >> + ODP_DBG("ping timer test %s\n", (pingarg.result == 0) ? "passed" : "failed"); >> + >> + printf("ODP ping timer test complete\n\n"); >> + >> + return 0; >> +} >> + >> -- >> 1.7.9.5 >> > > to start with: > Applying: timer:ping test application > /home/anders/src/odp/.git/rebase-apply/patch:424: new blank line at EOF. > + > warning: 1 line adds whitespace errors. > Trusted checkpatch.pl for this (:-
diff --git a/test/api_test/Makefile b/test/api_test/Makefile index bd99c50..0398cd2 100644 --- a/test/api_test/Makefile +++ b/test/api_test/Makefile @@ -11,6 +11,7 @@ ODP_ROOT = ../.. ODP_ATOMIC = odp_atomic ODP_SHM = odp_shm ODP_RING = odp_ring +ODP_TIM = odp_timer include $(ODP_ROOT)/Makefile.inc include ../Makefile.inc @@ -32,13 +33,18 @@ RING_OBJS = RING_OBJS += $(OBJ_DIR)/odp_common.o RING_OBJS += $(OBJ_DIR)/odp_ring_test.o -DEPS = $(ATOMIC_OBJS:.o=.d) $(SHM_OBJS:.o=.d) $(RING_OBJS:.o=.d) +TIM_OBJS = +TIM_OBJS += $(OBJ_DIR)/odp_common.o +TIM_OBJS += $(OBJ_DIR)/odp_timer_ping.o + +DEPS = $(ATOMIC_OBJS:.o=.d) $(SHM_OBJS:.o=.d) $(RING_OBJS:.o=.d) $(TIM_OBJS:.o=.d) .PHONY: all -all: $(OBJ_DIR) $(ODP_ATOMIC) $(ODP_SHM) $(ODP_RING) +all: $(OBJ_DIR) $(ODP_ATOMIC) $(ODP_SHM) $(ODP_RING) $(ODP_TIM) atomic: $(OBJ_DIR) $(ODP_ATOMIC) shm: $(OBJ_DIR) $(ODP_SHM) ring: $(OBJ_DIR) $(ODP_RING) +timer: $(OBJ_DIR) $(ODP_TIM) -include $(DEPS) @@ -64,12 +70,17 @@ $(ODP_RING): $(ODP_LIB) $(RING_OBJS) $(ECHO) Linking $< $(CC) $(LDFLAGS) $(RING_OBJS) $(ODP_LIB) $(STD_LIBS) -o $@ +$(ODP_TIM): $(ODP_LIB) $(TIM_OBJS) + $(ECHO) Linking $< + $(CC) $(LDFLAGS) $(TIM_OBJS) $(ODP_LIB) $(STD_LIBS) -o $@ + .PHONY: clean clean: $(RMDIR) $(OBJ_DIR) $(RM) $(ODP_ATOMIC) $(RM) $(ODP_SHM) $(RM) $(ODP_RING) + $(RM) $(ODP_TIM) $(MAKE) -C $(ODP_DIR) clean .PHONY: install @@ -78,3 +89,4 @@ install: install -m 0755 $(ODP_ATOMIC) $(DESTDIR)/share/odp/ install -m 0755 $(ODP_SHM) $(DESTDIR)/share/odp/ install -m 0755 $(ODP_RING) $(DESTDIR)/share/odp/ + install -m 0755 $(ODP_TIM) $(DESTDIR)/share/odp/ diff --git a/test/api_test/odp_common.h b/test/api_test/odp_common.h index e8201ac..f5183e1 100644 --- a/test/api_test/odp_common.h +++ b/test/api_test/odp_common.h @@ -20,6 +20,7 @@ typedef enum { ODP_SHM_TEST, ODP_RING_TEST_BASIC, ODP_RING_TEST_STRESS, + ODP_TIMER_PING_TEST, ODP_MAX_TEST } odp_test_case_e; diff --git a/test/api_test/odp_timer_ping.c b/test/api_test/odp_timer_ping.c new file mode 100644 index 0000000..df56072 --- /dev/null +++ b/test/api_test/odp_timer_ping.c @@ -0,0 +1,332 @@ +/* Copyright (c) 2014, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +/** + * @file + * + * ODP timer ping example application. + * application open PF_INET socket, every ping send request + * will arm timer for some duration, if ping_ack rxvd with + * time band.. listen thread will cancel timer and free the + * tmo_buffer.. otherwise timer expiration event will exit + * application lead to test failure.. + * - two thread used, one listener other one sender. + * - run ./odp_timer <ipadder> + * In ubuntu, you need run using sudo ./odp_timer <ipaddr> + * - so to tigger timeout explicitly.. ping with badipaddr + * Otherwise timeout may happen bcz of slow nw speed + */ + + +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/socket.h> +#include <resolv.h> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/ip_icmp.h> +#include <arpa/inet.h> + +#include <string.h> +#include <odp.h> +#include <odp_common.h> +#include <odp_timer.h> +#include <helper/odp_chksum.h> + +#define MSG_POOL_SIZE (4*1024*1024) +#define BUF_SIZE 8 +#define PING_CNT 10 + + +static odp_timer_t test_timer_ping; +static odp_timer_tmo_t test_ping_tmo; + +#define PKTSIZE 64 +struct packet { + struct icmphdr hdr; + char msg[PKTSIZE-sizeof(struct icmphdr)]; +}; + +int pid = -1; +struct protoent *proto; + +struct sockaddr_in dst_addr; + +/* local struct for ping_timer_thread argument */ +typedef struct { + pthrd_arg thrdarg; + int result; +} ping_arg_t; + +static int ping_sync_flag; + + +static void dump_icmp_pkt(void *buf, int bytes, int pkt_cnt) +{ + int i; + struct iphdr *ip = buf; + + ODP_DBG("---dump icmp pkt_cnt %d------\n", pkt_cnt); + for (i = 0; i < bytes; i++) { + if (!(i & 15)) + ODP_DBG("\n %x: ", i); + ODP_DBG("%d ", ((unsigned char *)buf)[i]); + } + ODP_DBG("\n"); + char addrstr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET, &ip->daddr, addrstr, sizeof(addrstr)); + ODP_DBG("byte %d, Ack rxvd for msg_cnt [%d] from %s\n", bytes, pkt_cnt, addrstr); +} + + +static int listen_to_pingack(void) +{ + int sd, i; + struct sockaddr_in addr; + unsigned char buf[1024]; + int bytes, len; + + sd = socket(PF_INET, SOCK_RAW, proto->p_proto); + if (sd < 0) { + ODP_ERR("Listener socket open failed\n"); + return -1; + } + + for (i = 0; i < PING_CNT; i++) { + len = sizeof(addr); + + bzero(buf, sizeof(buf)); + bytes = recvfrom(sd, buf, sizeof(buf), 0, + (struct sockaddr *)&addr, + (socklen_t *)&len); + if (bytes > 0) { + /* pkt rxvd therefore cancel the timeout */ + if (odp_timer_cancel_tmo(test_timer_ping, + test_ping_tmo) != 0) { + ODP_ERR("cancel_tmo failed ..exiting listner thread\n"); + return -1; + } + + /* cruel bad hack used for sender, listner ipc.. + * euwww.. FIXME .. + */ + ping_sync_flag = true; + dump_icmp_pkt(buf, bytes, i); + } else { + ODP_ERR("recvfrom operation failed for msg_cnt [%d]\n", i); + return -1; + } + } + + return 0; +} + + +static int send_ping_request(struct sockaddr_in *addr) +{ + const int val = 255; + uint32_t i, j; + int sd, cnt = 1; + struct packet pckt; + + uint64_t tick; + odp_queue_t queue; + odp_buffer_t buf; + + int thr; + thr = odp_thread_id(); + + sd = socket(PF_INET, SOCK_RAW, proto->p_proto); + if (sd < 0) { + ODP_ERR("Sender socket open failed\n"); + return -1; + } + + if (setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)) != 0) { + ODP_ERR("Error setting TTL option\n"); + return -1; + } + if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0) { + ODP_ERR("Request for nonblocking I/O failed\n"); + return -1; + } + + /* get the ping queue */ + queue = odp_queue_lookup("ping_timer_queue"); + + for (i = 0; i < PING_CNT; i++) { + /* prepare icmp pkt */ + bzero(&pckt, sizeof(pckt)); + pckt.hdr.type = ICMP_ECHO; + pckt.hdr.un.echo.id = pid; + + for (j = 0; j < sizeof(pckt.msg)-1; j++) + pckt.msg[j] = j+'0'; + + pckt.msg[j] = 0; + pckt.hdr.un.echo.sequence = cnt++; + pckt.hdr.checksum = odp_chksum(&pckt, sizeof(pckt)); + + + /* txmit the pkt */ + if (sendto(sd, &pckt, sizeof(pckt), 0, + (struct sockaddr *)addr, sizeof(*addr)) <= 0) { + ODP_ERR("sendto operation failed msg_cnt [%d]..exiting sender thread\n", i); + return -1; + } + printf(" icmp_sent msg_cnt %d\n", i); + + /* arm the timer */ + tick = odp_timer_current_tick(test_timer_ping); + ODP_DBG(" [%i] current tick %"PRIu64"\n", thr, tick); + + tick += 1000; + test_ping_tmo = odp_timer_absolute_tmo(test_timer_ping, tick, + queue, + ODP_BUFFER_INVALID); + + /* wait for timeout event */ + while ((buf = odp_queue_deq(queue) == ODP_BUFFER_INVALID)) { + /* flag true means ack rxvd.. a cruel hack as I + * am confused on method to get away from while + * loop in case of ack rxvd.. + * FIXME.. + */ + if (ping_sync_flag) { + ping_sync_flag = false; + ODP_DBG(" [%d] done :)!!\n", i); + buf = ODP_BUFFER_INVALID; + break; + } + } + + /* free tmo_buf for timeout case */ + if (buf != ODP_BUFFER_INVALID) { + ODP_DBG(" [%i] timeout msg_cnt [%i] (:-\n", thr, i); + odp_buffer_free(buf); + } + } + + return 0; +} + + +static void *ping_timer_thread(void *arg) +{ + ping_arg_t *parg = (ping_arg_t *)arg; + int thr; + + thr = odp_thread_id(); + + printf("Ping thread %i starts\n", thr); + + switch (parg->thrdarg.testcase) { + case ODP_TIMER_PING_TEST: + if (thr == 1) + if (send_ping_request(&dst_addr) < 0) + parg->result = -1; + if (thr == 2) + if (listen_to_pingack() < 0) + parg->result = -1; + break; + default: + ODP_ERR("Invalid test case [%d]\n", parg->thrdarg.testcase); + } + + + fflush(stdout); + + return parg; +} + +static int ping_init(int count, char *name[]) +{ + struct hostent *hname; + if (count != 2) { + ODP_ERR("usage: %s <hostaddr>\n", name[0]); + return -1; + } + + if (count > 1) { + pid = getpid(); + proto = getprotobyname("ICMP"); + hname = gethostbyname(name[1]); + bzero(&dst_addr, sizeof(dst_addr)); + dst_addr.sin_family = hname->h_addrtype; + dst_addr.sin_port = 0; + dst_addr.sin_addr.s_addr = *(long *)hname->h_addr; + } + printf("ping to addr %s\n", name[1]); + + return 0; +} + + +int main(int argc ODP_UNUSED, char *argv[] ODP_UNUSED) +{ + ping_arg_t pingarg; + odp_queue_t queue; + odp_buffer_pool_t pool; + void *pool_base; + + if (odp_test_global_init() != 0) + return -1; + + odp_print_system_info(); + + if (ping_init(argc, argv) != 0) + return -1; + + /* + * Create message pool + */ + pool_base = odp_shm_reserve("msg_pool", + MSG_POOL_SIZE, ODP_CACHE_LINE_SIZE); + + pool = odp_buffer_pool_create("msg_pool", pool_base, MSG_POOL_SIZE, + BUF_SIZE, + ODP_CACHE_LINE_SIZE, + ODP_BUFFER_TYPE_RAW); + if (pool == ODP_BUFFER_POOL_INVALID) { + ODP_ERR("Pool create failed.\n"); + return -1; + } + + /* + * Create a queue for timer test + */ + queue = odp_queue_create("ping_timer_queue", ODP_QUEUE_TYPE_SCHED, + NULL); + + if (queue == ODP_QUEUE_INVALID) { + ODP_ERR("Timer queue create failed.\n"); + return -1; + } + + test_timer_ping = odp_timer_create("ping_timer", pool, + 1000000, 1000000, 1000000000000); + odp_shm_print_all(); + + pingarg.thrdarg.testcase = ODP_TIMER_PING_TEST; + pingarg.thrdarg.numthrds = odp_sys_core_count(); + + pingarg.result = 0; + + /* Create and launch worker threads */ + odp_test_thread_create(ping_timer_thread, (pthrd_arg *)&pingarg); + + /* Wait for worker threads to exit */ + odp_test_thread_exit(&pingarg.thrdarg); + + ODP_DBG("ping timer test %s\n", (pingarg.result == 0) ? "passed" : "failed"); + + printf("ODP ping timer test complete\n\n"); + + return 0; +} +