Message ID | 1394889977-31193-2-git-send-email-santosh.shukla@linaro.org |
---|---|
State | Superseded |
Headers | show |
On 03/15/2014 05:26 PM, 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> > --- > test/api_test/Makefile | 16 +- > test/api_test/odp_common.h | 1 + > test/api_test/odp_timer_ping.c | 353 ++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 368 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..f03fc34 > --- /dev/null > +++ b/test/api_test/odp_timer_ping.c > @@ -0,0 +1,353 @@ > +/* 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> > + > +#define MSG_POOL_SIZE (4*1024*1024) > +#define BUF_SIZE 8 > + > + > +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 unsigned short checksum(void *b, int len) > +{ > + uint16_t *buf = b; > + unsigned int sum = 0; > + uint16_t result; > + > + for (sum = 0; len > 1; len -= 2) > + sum += *buf++; > + > + if (len == 1) > + sum += *(unsigned char *)buf; > + > + sum = (sum >> 16) + (sum & 0xFFFF); > + sum += (sum >> 16); > + result = ~sum; > + > + return result; > +} I think checksumm is good to go to helper/ include. This function is similar to my ipv4 chesum recalculation: https://patches.linaro.org/25538/ Maxim. > + > + > +static void dump_icmp_pkt(void *buf, int bytes, int pkt_cnt) > +{ > + int i; > + struct iphdr *ip; > + > + ip = buf; I think one line is better here then 3. I.e. 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]; > + > + 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 < 10; i++) { > + int bytes, len = sizeof(addr); > + please up int definitions to fit more kernel code style. it's it better to reuse ODP queues with raw sockets then creating raw sockets from stratch? > + 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 .. > + */ comment. Please describe the problem and make it more polish. > + ping_sync_flag = true; > + > + /* free tmo_buf */ > + odp_buffer_free(test_ping_tmo); comment above is not needed dues function name is exactly the same with the comment. > + > + 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 < 10; 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 = checksum(&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 == true) { 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; > +} > +
On 17 March 2014 12:08, Maxim Uvarov <maxim.uvarov@linaro.org> wrote: > On 03/15/2014 05:26 PM, 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> >> --- >> test/api_test/Makefile | 16 +- >> test/api_test/odp_common.h | 1 + >> test/api_test/odp_timer_ping.c | 353 >> ++++++++++++++++++++++++++++++++++++++++ >> 3 files changed, 368 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..f03fc34 >> --- /dev/null >> +++ b/test/api_test/odp_timer_ping.c >> @@ -0,0 +1,353 @@ >> +/* 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> >> + >> +#define MSG_POOL_SIZE (4*1024*1024) >> +#define BUF_SIZE 8 >> + >> + >> +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 unsigned short checksum(void *b, int len) >> +{ >> + uint16_t *buf = b; >> + unsigned int sum = 0; >> + uint16_t result; >> + >> + for (sum = 0; len > 1; len -= 2) >> + sum += *buf++; >> + >> + if (len == 1) >> + sum += *(unsigned char *)buf; >> + >> + sum = (sum >> 16) + (sum & 0xFFFF); >> + sum += (sum >> 16); >> + result = ~sum; >> + >> + return result; >> +} > > > I think checksumm is good to go to helper/ include. This function is similar > to my ipv4 chesum recalculation: > https://patches.linaro.org/25538/ > So should I reuse _ipv4_ chksum func or move this func to include/helper... > Maxim. > > >> + >> + >> +static void dump_icmp_pkt(void *buf, int bytes, int pkt_cnt) >> +{ >> + int i; >> + struct iphdr *ip; >> + >> + ip = buf; > > I think one line is better here then 3. I.e. struct iphdr *ip = buf; chkpatch doesn't complained to me.. your suggestion also fine for me. Okay. > > >> + 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]; >> + >> + 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 < 10; i++) { >> + int bytes, len = sizeof(addr); >> + > > please up int definitions to fit more kernel code style. again chkpatch quite on this.. can you paste link your refering for kernel coding style? > > > it's it better to reuse ODP queues with raw sockets then creating raw > sockets from stratch? make sense, I never looked at queue-wrapped-socket api. I'll do the changes.. > >> + 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 .. >> + */ > > comment. Please describe the problem and make it more polish. Situation is simple, flag helps to exit from sent_ping_thr in-case-of +ve-ping-ack from listener.. so no need to wait on queue. > >> + ping_sync_flag = true; >> + >> + /* free tmo_buf */ >> + odp_buffer_free(test_ping_tmo); > > comment above is not needed dues function name is exactly the same with the > comment. Okay. > >> + >> + 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 < 10; 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 = checksum(&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 == true) { > > if (ping_sync_flag) ? yup, much better. > >> + 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; >> +} >> + > > > -- > You received this message because you are subscribed to the Google Groups > "LNG ODP Sub-team - lng-odp@linaro.org" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to lng-odp+unsubscribe@linaro.org. > To post to this group, send email to lng-odp@linaro.org. > Visit this group at http://groups.google.com/a/linaro.org/group/lng-odp/. > To view this discussion on the web visit > https://groups.google.com/a/linaro.org/d/msgid/lng-odp/53269860.5060901%40linaro.org. > For more options, visit https://groups.google.com/a/linaro.org/d/optout.
On 17 March 2014 14:30, Santosh Shukla <santosh.shukla@linaro.org> wrote: > On 17 March 2014 12:08, Maxim Uvarov <maxim.uvarov@linaro.org> wrote: >> On 03/15/2014 05:26 PM, 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> >>> --- >>> test/api_test/Makefile | 16 +- >>> test/api_test/odp_common.h | 1 + >>> test/api_test/odp_timer_ping.c | 353 >>> ++++++++++++++++++++++++++++++++++++++++ >>> 3 files changed, 368 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..f03fc34 >>> --- /dev/null >>> +++ b/test/api_test/odp_timer_ping.c >>> @@ -0,0 +1,353 @@ >>> +/* 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> >>> + >>> +#define MSG_POOL_SIZE (4*1024*1024) >>> +#define BUF_SIZE 8 >>> + >>> + >>> +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 unsigned short checksum(void *b, int len) >>> +{ >>> + uint16_t *buf = b; >>> + unsigned int sum = 0; >>> + uint16_t result; >>> + >>> + for (sum = 0; len > 1; len -= 2) >>> + sum += *buf++; >>> + >>> + if (len == 1) >>> + sum += *(unsigned char *)buf; >>> + >>> + sum = (sum >> 16) + (sum & 0xFFFF); >>> + sum += (sum >> 16); >>> + result = ~sum; >>> + >>> + return result; >>> +} >> >> >> I think checksumm is good to go to helper/ include. This function is similar >> to my ipv4 chesum recalculation: >> https://patches.linaro.org/25538/ >> > > So should I reuse _ipv4_ chksum func or move this func to include/helper... Maxim, As discussed, Merge your patch titled "[ODP/PATCH] implement ipv4 checksum functions" Later I'll modify them so to use chksumming method only NOT ipv4 specific hdr or l3 hdr etc.. >> Maxim. >> >> >>> + >>> + >>> +static void dump_icmp_pkt(void *buf, int bytes, int pkt_cnt) >>> +{ >>> + int i; >>> + struct iphdr *ip; >>> + >>> + ip = buf; >> >> I think one line is better here then 3. I.e. struct iphdr *ip = buf; > > chkpatch doesn't complained to me.. your suggestion also fine for me. Okay. > >> >> >>> + 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]; >>> + >>> + 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 < 10; i++) { >>> + int bytes, len = sizeof(addr); >>> + >> >> please up int definitions to fit more kernel code style. > again chkpatch quite on this.. can you paste link your refering for > kernel coding style? > >> >> >> it's it better to reuse ODP queues with raw sockets then creating raw >> sockets from stratch? > > make sense, I never looked at queue-wrapped-socket api. I'll do the changes.. >> >>> + 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 .. >>> + */ >> >> comment. Please describe the problem and make it more polish. > > Situation is simple, flag helps to exit from sent_ping_thr in-case-of > +ve-ping-ack from listener.. so no need to wait on queue. >> >>> + ping_sync_flag = true; >>> + >>> + /* free tmo_buf */ >>> + odp_buffer_free(test_ping_tmo); >> >> comment above is not needed dues function name is exactly the same with the >> comment. > Okay. >> >>> + >>> + 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 < 10; 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 = checksum(&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 == true) { >> >> if (ping_sync_flag) ? > yup, much better. > >> >>> + 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; >>> +} >>> + >> >> >> -- >> You received this message because you are subscribed to the Google Groups >> "LNG ODP Sub-team - lng-odp@linaro.org" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to lng-odp+unsubscribe@linaro.org. >> To post to this group, send email to lng-odp@linaro.org. >> Visit this group at http://groups.google.com/a/linaro.org/group/lng-odp/. >> To view this discussion on the web visit >> https://groups.google.com/a/linaro.org/d/msgid/lng-odp/53269860.5060901%40linaro.org. >> For more options, visit https://groups.google.com/a/linaro.org/d/optout.
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..f03fc34 --- /dev/null +++ b/test/api_test/odp_timer_ping.c @@ -0,0 +1,353 @@ +/* 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> + +#define MSG_POOL_SIZE (4*1024*1024) +#define BUF_SIZE 8 + + +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 unsigned short checksum(void *b, int len) +{ + uint16_t *buf = b; + unsigned int sum = 0; + uint16_t result; + + for (sum = 0; len > 1; len -= 2) + sum += *buf++; + + if (len == 1) + sum += *(unsigned char *)buf; + + sum = (sum >> 16) + (sum & 0xFFFF); + sum += (sum >> 16); + result = ~sum; + + return result; +} + + +static void dump_icmp_pkt(void *buf, int bytes, int pkt_cnt) +{ + int i; + struct iphdr *ip; + + 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]; + + 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 < 10; i++) { + int bytes, 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; + + /* free tmo_buf */ + odp_buffer_free(test_ping_tmo); + + 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 < 10; 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 = checksum(&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 == true) { + 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; +} +