diff mbox

[ODP/PATCH,2/2] timer : ping test application

Message ID 1394889977-31193-2-git-send-email-santosh.shukla@linaro.org
State Superseded
Headers show

Commit Message

Santosh Shukla March 15, 2014, 1:26 p.m. UTC
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

Comments

Maxim Uvarov March 17, 2014, 6:38 a.m. UTC | #1
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;
> +}
> +
Santosh Shukla March 17, 2014, 9 a.m. UTC | #2
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.
Santosh Shukla March 17, 2014, 10:26 a.m. UTC | #3
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 mbox

Patch

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;
+}
+