Message ID | 1398762193-20833-1-git-send-email-weilong.chen@linaro.org |
---|---|
State | Rejected |
Headers | show |
On 2014-04-29 17:03, Weilong Chen wrote: > odp_generator can send/receive udp packets, or works like ping. > Work mode: > 1.send udp packets > odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 --dstmac 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m u > 2.receive udp packets > odp_generator -I eth0 -m r > 3.work likes ping > odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 --dstmac 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m p > > Mandatory OPTIONS: > -I, --interface Eth interfaces (comma-separated, no spaces) > -a, --srcmac src mac address > -b, --dstmac dst mac address > -c, --srcip src ip address > -d, --dstip dst ip address > -s, --packetsize payload length of the packets > -m, --mode work mode: send udp(u), receive(r), send icmp(p) > -n, --count the number of packets to be send > -t, --timeout only for ping mode, wait ICMP reply timeout seconds > -i, --interval wait interval ms between sending each packet > default is 1000ms. 0 for flood mode > > Signed-off-by: Weilong Chen <weilong.chen@linaro.org> Couldn't build with -std=C99 $ make CC=gcc CFLAGS="-std=c99" Compiling odp_generator.c gcc -c -MD -DODP_DEBUG=1 -O3 -pthread -W -Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wold-style-definition -Wpointer-arith -Wcast-align -Wnested-externs -Wcast-qual -Wformat-nonliteral -Wformat-security -Wundef -Wwrite-strings -I../../include -I../../platform/linux-generic/include/api -std=c99 -o obj/odp_generator.o odp_generator.c odp_generator.c: In function ‘gen_send_thread’: odp_generator.c:341:4: error: implicit declaration of function ‘usleep’ [-Werror=implicit-function-declaration] usleep(args->appl.interval * 1000); ^ odp_generator.c:341:4: error: nested extern declaration of ‘usleep’ [-Werror=nested-externs] odp_generator.c: In function ‘parse_args’: odp_generator.c:727:5: error: implicit declaration of function ‘strtok_r’ [-Werror=implicit-function-declaration] token = strtok_r(str, ",", &save); ^ odp_generator.c:727:5: error: nested extern declaration of ‘strtok_r’ [-Werror=nested-externs] odp_generator.c:727:11: error: assignment makes pointer from integer without a cast [-Werror] token = strtok_r(str, ",", &save); ^ odp_generator.c:745:11: error: assignment makes pointer from integer without a cast [-Werror] token = strtok_r(str, ",", &save); ^ cc1: all warnings being treated as errors make: *** [obj/odp_generator.o] Error 1 Cheers, Anders
Compiling odp_generator.c armeb-linux-gnueabihf-gcc -c -MD -DODP_DEBUG=1 -O3 -pthread -W -Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wold-style-definition -Wpointer-arith -Wcast-align -Wnested-externs -Wcast-qual -Wformat-nonliteral -Wformat-security -Wundef -Wwrite-strings -I/opt/LINARO/ODPrelease/ReleaseCommit2/odp2.git/build/include -I/opt/LINARO/ODPrelease/ReleaseCommit2/odp2.git/build/include/api -o obj/odp_generator.o odp_generator.c In file included from odp_generator.c:25:0: /opt/LINARO/ODPrelease/ReleaseCommit2/odp2.git/build/include/helper/odp_udp.h: In function 'odp_ipv4_udp_chksum': /opt/LINARO/ODPrelease/ReleaseCommit2/odp2.git/build/include/helper/odp_udp.h:61:8: error: cast increases required alignment of target type [-Werror=cast-align] buf = (unsigned short *)udph; ^ odp_generator.c: In function 'pack_icmp_pkt': odp_generator.c:270:9: error: cast increases required alignment of target type [-Werror=cast-align] tval = (struct timeval *)(buf + ODP_ETHHDR_LEN + ODP_IPV4HDR_LEN + ^ odp_generator.c:276:28: error: cast increases required alignment of target type [-Werror=cast-align] icmp->chksum = odp_chksum((unsigned short *)icmp, args->appl.payload + ^ odp_generator.c: In function 'gen_send_thread': odp_generator.c:339:11: error: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'odp_atomic_u64_t' [-Werror=format=] thr, counters.seq, counters.seq%0xffff); ^ odp_generator.c:339:11: error: format '%lu' expects argument of type 'long unsigned int', but argument 4 has type 'long long unsigned int' [-Werror=format=] odp_generator.c:346:11: error: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'odp_atomic_u64_t' [-Werror=format=] thr, counters.seq, counters.seq%0xffff); ^ odp_generator.c:346:11: error: format '%lu' expects argument of type 'long unsigned int', but argument 4 has type 'long long unsigned int' [-Werror=format=] odp_generator.c:367:3: error: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'odp_atomic_u64_t' [-Werror=format=] printf(" [%02i] total send:%lu\n", thr, counters.seq); ^ odp_generator.c:370:10: error: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'odp_atomic_u64_t' [-Werror=format=] thr, counters.seq, counters.icmp); ^ odp_generator.c:370:10: error: format '%lu' expects argument of type 'long unsigned int', but argument 4 has type 'odp_atomic_u64_t' [-Werror=format=] odp_generator.c: In function 'print_pkts': odp_generator.c:427:14: error: cast increases required alignment of target type [-Werror=cast-align] tvsend = (struct timeval *)(buf + offset + ^ cc1: all warnings being treated as errors On 04/29/2014 01:03 PM, Weilong Chen wrote: > odp_generator can send/receive udp packets, or works like ping. > Work mode: > 1.send udp packets > odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 --dstmac 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m u > 2.receive udp packets > odp_generator -I eth0 -m r > 3.work likes ping > odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 --dstmac 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m p > > Mandatory OPTIONS: > -I, --interface Eth interfaces (comma-separated, no spaces) > -a, --srcmac src mac address > -b, --dstmac dst mac address > -c, --srcip src ip address > -d, --dstip dst ip address > -s, --packetsize payload length of the packets > -m, --mode work mode: send udp(u), receive(r), send icmp(p) > -n, --count the number of packets to be send > -t, --timeout only for ping mode, wait ICMP reply timeout seconds > -i, --interval wait interval ms between sending each packet > default is 1000ms. 0 for flood mode > > Signed-off-by: Weilong Chen <weilong.chen@linaro.org> > --- > .gitignore | 1 + > test/Makefile | 3 + > test/generator/Makefile | 46 ++ > test/generator/odp_generator.c | 921 ++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 971 insertions(+) > create mode 100644 test/generator/Makefile > create mode 100644 test/generator/odp_generator.c > > diff --git a/.gitignore b/.gitignore > index 781932c..b4c7017 100644 > --- a/.gitignore > +++ b/.gitignore > @@ -16,3 +16,4 @@ test/api_test/odp_shm > test/api_test/odp_ring > test/api_test/odp_timer > test/timer/odp_timer_test > +test/generator/odp_generator > diff --git a/test/Makefile b/test/Makefile > index 9e3c482..cc3f4e9 100644 > --- a/test/Makefile > +++ b/test/Makefile > @@ -10,6 +10,7 @@ all: > $(MAKE) -C packet > $(MAKE) -C packet_netmap > $(MAKE) -C timer > + $(MAKE) -C generator > > .PHONY: clean > clean: > @@ -18,6 +19,7 @@ clean: > $(MAKE) -C packet clean > $(MAKE) -C packet_netmap clean > $(MAKE) -C timer clean > + $(MAKE) -C generator clean > > .PHONY: install > install: > @@ -26,3 +28,4 @@ install: > $(MAKE) -C packet install > $(MAKE) -C packet_netmap install > $(MAKE) -C timer install > + $(MAKE) -C generator install > diff --git a/test/generator/Makefile b/test/generator/Makefile > new file mode 100644 > index 0000000..d1f288d > --- /dev/null > +++ b/test/generator/Makefile > @@ -0,0 +1,46 @@ > +# Copyright (c) 2014, Linaro Limited > +# All rights reserved. > +# > +# SPDX-License-Identifier: BSD-3-Clause > + > +ODP_ROOT = ../.. > +ODP_APP = odp_generator > + > +include $(ODP_ROOT)/Makefile.inc > +include ../Makefile.inc > + > +.PHONY: default > +default: $(OBJ_DIR) $(ODP_APP) > + > +OBJS = > +OBJS += $(OBJ_DIR)/odp_generator.o > + > +DEPS = $(OBJS:.o=.d) > + > +-include $(DEPS) > + > + > +# > +# Compile rules > +# > +$(OBJ_DIR)/%.o: %.c > + $(ECHO) Compiling $< > + $(CC) -c -MD $(EXTRA_CFLAGS) $(CFLAGS) -o $@ $< > + > +# > +# Link rule > +# > +$(ODP_APP): $(ODP_LIB) $(OBJS) > + $(ECHO) Linking $< > + $(CC) $(LDFLAGS) $(OBJS) $(ODP_LIB) $(STD_LIBS) -o $@ > + > +.PHONY: clean > +clean: > + $(RMDIR) $(OBJ_DIR) > + $(RM) $(ODP_APP) > + $(MAKE) -C $(ODP_DIR) clean > + > +.PHONY: install > +install: > + install -d $(DESTDIR)/share/odp > + install -m 0755 $(ODP_APP) $(DESTDIR)/share/odp/ > diff --git a/test/generator/odp_generator.c b/test/generator/odp_generator.c > new file mode 100644 > index 0000000..10b60ca > --- /dev/null > +++ b/test/generator/odp_generator.c > @@ -0,0 +1,921 @@ > +/* Copyright (c) 2014, Linaro Limited > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > +/** > + * @file > + * > + * @example odp_generator.c ODP loopback demo application > + */ > + > +#include <stdlib.h> > +#include <string.h> > +#include <getopt.h> > +#include <unistd.h> > +#include <sys/time.h> > + > +#include <odp.h> > +#include <odp_packet_io.h> > +#include <helper/odp_linux.h> > +#include <helper/odp_packet_helper.h> > +#include <helper/odp_eth.h> > +#include <helper/odp_ip.h> > +#include <helper/odp_udp.h> > +#include <helper/odp_icmp.h> > + > +#define MAX_WORKERS 32 /**< max number of works */ > +#define SHM_PKT_POOL_SIZE (512*2048) /**< pkt pool size */ > +#define SHM_PKT_POOL_BUF_SIZE 1856 /**< pkt pool buf size */ > + > +#define APPL_MODE_UDP 0 /**< UDP mode */ > +#define APPL_MODE_PING 1 /**< ping mode */ > +#define APPL_MODE_RCV 2 /**< receive mode */ > + > +/** print appl mode */ > +#define PRINT_APPL_MODE(x) printf("%s(%i)\n", #x, (x)) > + > +/** Get rid of path in filename - only for unix-type paths using '/' */ > +#define NO_PATH(file_name) (strrchr((file_name), '/') ? \ > + strrchr((file_name), '/') + 1 : (file_name)) > +/** > + * Parsed command line application arguments > + */ > +typedef struct { > + int core_count; /**< system core count */ > + int if_count; /**< Number of interfaces to be used */ > + char **if_names; /**< Array of pointers to interface names */ > + odp_buffer_pool_t pool; /**< Buffer pool for packet IO */ > + odp_ethaddr_t srcmac; /**< src mac addr */ > + odp_ethaddr_t dstmac; /**< dest mac addr */ > + unsigned int srcip; /**< src ip addr */ > + unsigned int dstip; /**< dest ip addr */ > + int mode; /**< work mode */ > + int number; /**< packets number to be sent */ > + int payload; /**< data len */ > + int timeout; /**< wait time */ > + int interval; /**< wait interval ms between sending each packet */ > +} appl_args_t; > + > +/** > + * counters > +*/ > +struct { > + odp_atomic_u64_t seq; /**< ip seq to be send */ > + odp_atomic_u64_t ip; /**< ip packets */ > + odp_atomic_u64_t udp; /**< udp packets */ > + odp_atomic_u64_t icmp; /**< icmp packets */ > +} counters; > + > +/** * Thread specific arguments > + */ > +typedef struct { > + char *pktio_dev; /**< Interface name to use */ > + odp_buffer_pool_t pool; /**< Buffer pool for packet IO */ > + int mode; /**< Thread mode */ > +} thread_args_t; > + > +/** > + * Grouping of both parsed CL args and thread specific args - alloc together > + */ > +typedef struct { > + /** Application (parsed) arguments */ > + appl_args_t appl; > + /** Thread specific arguments */ > + thread_args_t thread[MAX_WORKERS]; > +} args_t; > + > +/** Global pointer to args */ > +static args_t *args; > + > +/* helper funcs */ > +static void parse_args(int argc, char *argv[], appl_args_t *appl_args); > +static void print_info(char *progname, appl_args_t *appl_args); > +static void usage(char *progname); > +static int scan_ip(char *buf, unsigned int *paddr); > +static int scan_mac(char *in, odp_ethaddr_t *des); > +static void tv_sub(struct timeval *recvtime, struct timeval *sendtime); > + > +/** > + * Scan ip > + * Parse ip address. > + * > + * @param buf ip address string xxx.xxx.xxx.xx > + * @param paddr ip address for odp_packet > + * @return 1 success, 0 failed > +*/ > +int scan_ip(char *buf, unsigned int *paddr) > +{ > + int part1, part2, part3, part4; > + char tail = 0; > + int field; > + > + if (buf == NULL) > + return 0; > + > + field = sscanf(buf, "%d . %d . %d . %d %c", > + &part1, &part2, &part3, &part4, &tail); > + > + if (field < 4 || field > 5) { > + printf("expect 4 field,get %d/n", field); > + return 0; > + } > + > + if (tail != 0) { > + printf("ip address mixed with non number/n"); > + return 0; > + } > + > + if ((part1 >= 0 && part1 <= 255) && (part2 >= 0 && part2 <= 255) && > + (part3 >= 0 && part3 <= 255) && (part4 >= 0 && part4 <= 255)) { > + if (paddr) > + *paddr = part1 << 24 | part2 << 16 | part3 << 8 | part4; > + return 1; > + } else { > + printf("not good ip %d:%d:%d:%d/n", part1, part2, part3, part4); > + } > + > + return 0; > +} > + > +/** > + * Scan mac addr form string > + * > + * @param in mac string > + * @param des mac for odp_packet > + * @return 1 success, 0 failed > + */ > +int scan_mac(char *in, odp_ethaddr_t *des) > +{ > + int field; > + int i; > + unsigned int mac[7]; > + > + field = sscanf(in, "%2x:%2x:%2x:%2x:%2x:%2x", > + &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); > + > + for (i = 0; i < 6; i++) > + des->addr[i] = mac[i]; > + > + if (field != 6) > + return 0; > + return 1; > +} > + > +/** > + * set up an udp packet > + * > + * @param obuf packet buffer > +*/ > +static void pack_udp_pkt(odp_buffer_t obuf) > +{ > + char *buf; > + int max; > + odp_packet_t pkt; > + odp_ethhdr_t *eth; > + odp_ipv4hdr_t *ip; > + odp_udphdr_t *udp; > + unsigned short seq; > + > + buf = odp_buffer_addr(obuf); > + if (buf == NULL) > + return; > + max = odp_buffer_size(obuf); > + if (max <= 0) > + return; > + > + pkt = odp_packet_from_buffer(obuf); > + /* ether */ > + odp_packet_set_l2_offset(pkt, 0); > + eth = (odp_ethhdr_t *)buf; > + memcpy((char *)eth->src.addr, args->appl.srcmac.addr, ODP_ETHADDR_LEN); > + memcpy((char *)eth->dst.addr, args->appl.dstmac.addr, ODP_ETHADDR_LEN); > + eth->type = odp_cpu_to_be_16(ODP_ETHTYPE_IPV4); > + /* ip */ > + odp_packet_set_l3_offset(pkt, ODP_ETHHDR_LEN); > + ip = (odp_ipv4hdr_t *)(buf + ODP_ETHHDR_LEN); > + ip->dst_addr = odp_cpu_to_be_32(args->appl.dstip); > + ip->src_addr = odp_cpu_to_be_32(args->appl.srcip); > + ip->ver_ihl = ODP_IPV4 << 4 | ODP_IPV4HDR_IHL_MIN; > + ip->tot_len = odp_cpu_to_be_16(args->appl.payload + ODP_UDPHDR_LEN + > + ODP_IPV4HDR_LEN); > + ip->proto = ODP_IPPROTO_UDP; > + seq = odp_atomic_fetch_add_u64(&counters.seq, 1) % 0xFFFF; > + ip->id = odp_cpu_to_be_16(seq); > + ip->chksum = 0; > + odp_ipv4_csum_update(pkt); > + /* udp */ > + odp_packet_set_l4_offset(pkt, ODP_ETHHDR_LEN + ODP_IPV4HDR_LEN); > + udp = (odp_udphdr_t *)(buf + ODP_ETHHDR_LEN + ODP_IPV4HDR_LEN); > + udp->src_port = 0; > + udp->dst_port = 0; > + udp->length = odp_cpu_to_be_16(args->appl.payload + ODP_UDPHDR_LEN); > + udp->chksum = 0; > + udp->chksum = odp_ipv4_udp_chksum(pkt); > + odp_packet_set_len(pkt, args->appl.payload + ODP_UDPHDR_LEN + > + ODP_IPV4HDR_LEN + ODP_ETHHDR_LEN); > +} > + > +/** > + * Set up an icmp packet > + * > + * @param obuf packet buffer > +*/ > +static void pack_icmp_pkt(odp_buffer_t obuf) > +{ > + char *buf; > + int max; > + odp_packet_t pkt; > + odp_ethhdr_t *eth; > + odp_ipv4hdr_t *ip; > + odp_icmphdr_t *icmp; > + struct timeval *tval; > + unsigned short seq; > + > + buf = odp_buffer_addr(obuf); > + if (buf == NULL) > + return; > + max = odp_buffer_size(obuf); > + if (max <= 0) > + return; > + > + args->appl.payload = 56; > + pkt = odp_packet_from_buffer(obuf); > + /* ether */ > + odp_packet_set_l2_offset(pkt, 0); > + eth = (odp_ethhdr_t *)buf; > + memcpy((char *)eth->src.addr, args->appl.srcmac.addr, ODP_ETHADDR_LEN); > + memcpy((char *)eth->dst.addr, args->appl.dstmac.addr, ODP_ETHADDR_LEN); > + eth->type = odp_cpu_to_be_16(ODP_ETHTYPE_IPV4); > + /* ip */ > + odp_packet_set_l3_offset(pkt, ODP_ETHHDR_LEN); > + ip = (odp_ipv4hdr_t *)(buf + ODP_ETHHDR_LEN); > + ip->dst_addr = odp_cpu_to_be_32(args->appl.dstip); > + ip->src_addr = odp_cpu_to_be_32(args->appl.srcip); > + ip->ver_ihl = ODP_IPV4 << 4 | ODP_IPV4HDR_IHL_MIN; > + ip->tot_len = odp_cpu_to_be_16(args->appl.payload + ODP_ICMPHDR_LEN + > + ODP_IPV4HDR_LEN); > + ip->proto = ODP_IPPROTO_ICMP; > + seq = odp_atomic_fetch_add_u64(&counters.seq, 1) % 0xffff; > + ip->id = odp_cpu_to_be_16(seq); > + ip->chksum = 0; > + odp_ipv4_csum_update(pkt); > + /* icmp */ > + icmp = (odp_icmphdr_t *)(buf + ODP_ETHHDR_LEN + ODP_IPV4HDR_LEN); > + icmp->type = ICMP_ECHO; > + icmp->code = 0; > + icmp->un.echo.id = 0; > + icmp->un.echo.sequence = ip->id; > + tval = (struct timeval *)(buf + ODP_ETHHDR_LEN + ODP_IPV4HDR_LEN + > + ODP_ICMPHDR_LEN); > + /* TODO This should be changed to use an > + * ODP timer API once one exists. */ > + gettimeofday(tval, NULL); > + icmp->chksum = 0; > + icmp->chksum = odp_chksum((unsigned short *)icmp, args->appl.payload + > + ODP_ICMPHDR_LEN); > + > + odp_packet_set_len(pkt, args->appl.payload + ODP_ICMPHDR_LEN + > + ODP_IPV4HDR_LEN + ODP_ETHHDR_LEN); > +} > + > +/** > + * Packet IO loopback worker thread using ODP queues > + * > + * @param arg thread arguments of type 'thread_args_t *' > + */ > + > +static void *gen_send_thread(void *arg) > +{ > + int thr; > + odp_pktio_t pktio; > + thread_args_t *thr_args; > + odp_queue_t outq_def; > + odp_pktio_params_t params; > + socket_params_t *sock_params = ¶ms.sock_params; > + > + odp_buffer_t buf; > + > + thr = odp_thread_id(); > + thr_args = arg; > + > + /* Open a packet IO instance for this thread */ > + sock_params->type = 1; > + pktio = odp_pktio_open(thr_args->pktio_dev, thr_args->pool, ¶ms); > + if (pktio == ODP_PKTIO_INVALID) { > + ODP_ERR(" [%02i] Error: pktio create failed\n", thr); > + return NULL; > + } > + > + outq_def = odp_pktio_outq_getdef(pktio); > + if (outq_def == ODP_QUEUE_INVALID) { > + ODP_ERR(" [%02i] Error: def output-Q query\n", thr); > + return NULL; > + } > + > + printf(" [%02i] created mode: SEND\n", thr); > + for (;;) { > + int err; > + buf = odp_buffer_alloc(thr_args->pool); > + if (!odp_buffer_is_valid(buf)) { > + ODP_ERR(" [%2i] alloc_single failed\n", thr); > + return NULL; > + } > + > + if (args->appl.mode == APPL_MODE_UDP) > + pack_udp_pkt(buf); > + else if (args->appl.mode == APPL_MODE_PING) > + pack_icmp_pkt(buf); > + > + err = odp_queue_enq(outq_def, buf); > + if (err != 0) { > + ODP_ERR(" [%02i] send pkt err!\n", thr); > + return NULL; > + } > + > + if (args->appl.interval != 0) { > + printf(" [%02i] send pkt no:%lu seq %lu\n", > + thr, counters.seq, counters.seq%0xffff); > + /* TODO use odp timer */ > + usleep(args->appl.interval * 1000); > + } else { > + /* TODO maybe need a rating control */ > + /* flood mode use '\r' instead of '\n' */ > + printf(" [%02i] send pkt no:%lu seq %lu\r", > + thr, counters.seq, counters.seq%0xffff); > + } > + if (args->appl.number != -1 && counters.seq > + >= (unsigned int)args->appl.number) { > + break; > + } > + } > + > + /* receive number of reply pks until timeout */ > + if (args->appl.mode == APPL_MODE_PING && args->appl.number > 0) { > + while (args->appl.timeout >= 0) { > + if (counters.icmp >= (unsigned int)args->appl.number) > + break; > + /* TODO use odp timer */ > + sleep(1); > + args->appl.timeout--; > + } > + } > + > + /* print info */ > + if (args->appl.mode == APPL_MODE_UDP) { > + printf(" [%02i] total send:%lu\n", thr, counters.seq); > + } else if (args->appl.mode == APPL_MODE_PING) { > + printf(" [%02i] total send:%lu,total receiver %lu\n", > + thr, counters.seq, counters.icmp); > + } > + return arg; > +} > + > +/** > + * Print odp packets > + * > + * @param thr worker id > + * @param pkt_tbl packets to be print > + * @param len packet number > + */ > +static void print_pkts(int thr, odp_packet_t pkt_tbl[], unsigned len) > +{ > + odp_packet_t pkt; > + char *buf; > + odp_ipv4hdr_t *ip; > + odp_udphdr_t *udp; > + odp_icmphdr_t *icmp; > + struct timeval tvrecv; > + struct timeval *tvsend; > + double rtt; > + unsigned i; > + size_t offset; > + char msg[1024]; > + int rlen; > + for (i = 0; i < len; ++i) { > + pkt = pkt_tbl[i]; > + rlen = 0; > + > + /* only ip pkts */ > + if (!odp_packet_inflag_ipv4(pkt)) > + continue; > + > + odp_atomic_inc_u64(&counters.ip); > + rlen += sprintf(msg, "receive Packet proto:IP "); > + buf = odp_buffer_addr(odp_buffer_from_packet(pkt)); > + ip = (odp_ipv4hdr_t *)(buf + odp_packet_l3_offset(pkt)); > + rlen += sprintf(msg + rlen, "id %d ", > + odp_be_to_cpu_16(ip->id)); > + offset = odp_packet_l4_offset(pkt); > + > + /* udp */ > + if (ip->proto == ODP_IPPROTO_UDP) { > + odp_atomic_inc_u64(&counters.udp); > + udp = (odp_udphdr_t *)(buf + offset); > + rlen += sprintf(msg + rlen, "UDP payload %d ", > + odp_be_to_cpu_16(udp->length) - > + ODP_UDPHDR_LEN); > + } > + > + /* icmp */ > + if (ip->proto == ODP_IPPROTO_ICMP) { > + icmp = (odp_icmphdr_t *)(buf + offset); > + /* echo reply */ > + if (icmp->type == ICMP_ECHOREPLY) { > + odp_atomic_inc_u64(&counters.icmp); > + tvsend = (struct timeval *)(buf + offset + > + ODP_ICMPHDR_LEN); > + /* TODO This should be changed to use an > + * ODP timer API once one exists. */ > + gettimeofday(&tvrecv, NULL); > + tv_sub(&tvrecv, tvsend); > + rtt = tvrecv.tv_sec*1000 + tvrecv.tv_usec/1000; > + rlen += sprintf(msg + rlen, > + "ICMP Echo Reply seq %d time %.1f ", > + odp_be_to_cpu_16(icmp->un.echo.sequence) > + , rtt); > + } else if (icmp->type == ICMP_ECHO) { > + rlen += sprintf(msg + rlen, > + "Icmp Echo Request"); > + } > + } > + > + msg[rlen] = '\0'; > + printf(" [%02i] %s\n", thr, msg); > + } > +} > + > +/** > + * Main receive funtion > + * > + * @param arg thread arguments of type 'thread_args_t *' > + */ > +static void *gen_recv_thread(void *arg) > +{ > + int thr; > + odp_pktio_t pktio; > + thread_args_t *thr_args; > + odp_queue_t inq_def; > + odp_pktio_params_t params; > + char inq_name[ODP_QUEUE_NAME_LEN]; > + odp_queue_param_t qparam; > + socket_params_t *sock_params = ¶ms.sock_params; > + > + odp_packet_t pkt; > + odp_buffer_t buf; > + > + thr = odp_thread_id(); > + thr_args = arg; > + > + /* Open a packet IO instance for this thread */ > + sock_params->type = 1; > + pktio = odp_pktio_open(thr_args->pktio_dev, thr_args->pool, ¶ms); > + if (pktio == ODP_PKTIO_INVALID) { > + ODP_ERR(" [%02i] Error: pktio create failed\n", thr); > + return NULL; > + } > + > + int ret; > + qparam.sched.prio = ODP_SCHED_PRIO_DEFAULT; > + qparam.sched.sync = ODP_SCHED_SYNC_ATOMIC; > + qparam.sched.group = ODP_SCHED_GROUP_DEFAULT; > + snprintf(inq_name, sizeof(inq_name), "%i-pktio_inq_def", (int)pktio); > + inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0'; > + inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN, &qparam); > + if (inq_def == ODP_QUEUE_INVALID) { > + ODP_ERR(" [%02i] Error: pktio queue creation failed\n", thr); > + return NULL; > + } > + > + ret = odp_pktio_inq_setdef(pktio, inq_def); > + if (ret != 0) { > + ODP_ERR(" [%02i] Error: default input-Q setup\n", thr); > + return NULL; > + } > + > + printf(" [%02i] created mode: RECEIVE\n", thr); > + for (;;) { > + /* Use schedule to get buf from any input queue */ > + buf = odp_schedule(NULL, ODP_SCHED_WAIT); > + > + pkt = odp_packet_from_buffer(buf); > + /* Drop packets with errors */ > + if (odp_unlikely(odp_packet_error(pkt))) { > + odp_packet_free(pkt); > + continue; > + } > + > + print_pkts(thr, &pkt, 1); > + > + odp_packet_free(pkt); > + } > + > + return arg; > +} > +/** > + * ODP packet example main function > + */ > +int main(int argc, char *argv[]) > +{ > + odp_linux_pthread_t thread_tbl[MAX_WORKERS]; > + odp_buffer_pool_t pool; > + int thr_id; > + int num_workers; > + void *pool_base; > + int i; > + int first_core; > + int core_count; > + > + /* Init ODP before calling anything else */ > + if (odp_init_global()) { > + ODP_ERR("Error: ODP global init failed.\n"); > + exit(EXIT_FAILURE); > + } > + > + /* init counters */ > + odp_atomic_init_u64(&counters.seq); > + odp_atomic_init_u64(&counters.ip); > + odp_atomic_init_u64(&counters.udp); > + odp_atomic_init_u64(&counters.icmp); > + > + /* Reserve memory for args from shared mem */ > + args = odp_shm_reserve("shm_args", sizeof(args_t), ODP_CACHE_LINE_SIZE); > + if (args == NULL) { > + ODP_ERR("Error: shared mem alloc failed.\n"); > + exit(EXIT_FAILURE); > + } > + memset(args, 0, sizeof(*args)); > + > + /* Parse and store the application arguments */ > + parse_args(argc, argv, &args->appl); > + > + /* Print both system and application information */ > + print_info(NO_PATH(argv[0]), &args->appl); > + > + core_count = odp_sys_core_count(); > + num_workers = core_count; > + > + if (args->appl.core_count) > + num_workers = args->appl.core_count; > + > + if (num_workers > MAX_WORKERS) > + num_workers = MAX_WORKERS; > + > + /* ping mode need two worker */ > + if (args->appl.mode == APPL_MODE_PING) > + num_workers = 2; > + > + printf("Num worker threads: %i\n", num_workers); > + > + /* > + * By default core #0 runs Linux kernel background tasks. > + * Start mapping thread from core #1 > + */ > + first_core = 1; > + > + if (core_count == 1) > + first_core = 0; > + > + printf("First core: %i\n\n", first_core); > + > + /* Init this thread */ > + thr_id = odp_thread_create(0); > + odp_init_local(thr_id); > + > + /* Create packet pool */ > + pool_base = odp_shm_reserve("shm_packet_pool", > + SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE); > + if (pool_base == NULL) { > + ODP_ERR("Error: packet pool mem alloc failed.\n"); > + exit(EXIT_FAILURE); > + } > + > + pool = odp_buffer_pool_create("packet_pool", pool_base, > + SHM_PKT_POOL_SIZE, > + SHM_PKT_POOL_BUF_SIZE, > + ODP_CACHE_LINE_SIZE, > + ODP_BUFFER_TYPE_PACKET); > + if (pool == ODP_BUFFER_POOL_INVALID) { > + ODP_ERR("Error: packet pool create failed.\n"); > + exit(EXIT_FAILURE); > + } > + odp_buffer_pool_print(pool); > + > + /* Create and init worker threads */ > + memset(thread_tbl, 0, sizeof(thread_tbl)); > + > + if (args->appl.mode == APPL_MODE_PING) { > + args->thread[1].pktio_dev = args->appl.if_names[0]; > + args->thread[1].pool = pool; > + args->thread[1].mode = args->appl.mode; > + odp_linux_pthread_create(thread_tbl, 1, 0, > + gen_recv_thread, &args->thread[1]); > + > + args->thread[0].pktio_dev = args->appl.if_names[0]; > + args->thread[0].pool = pool; > + args->thread[0].mode = args->appl.mode; > + odp_linux_pthread_create(thread_tbl, 1, 0, > + gen_send_thread, &args->thread[0]); > + > + /* only wait send thread to join */ > + num_workers = 1; > + } else { > + for (i = 0; i < num_workers; ++i) { > + void *(*thr_run_func) (void *); > + int core; > + int if_idx; > + > + core = (first_core + i) % core_count; > + > + if_idx = i % args->appl.if_count; > + > + args->thread[i].pktio_dev = args->appl.if_names[if_idx]; > + args->thread[i].pool = pool; > + args->thread[i].mode = args->appl.mode; > + > + if (args->appl.mode == APPL_MODE_UDP) { > + thr_run_func = gen_send_thread; > + } else if (args->appl.mode == APPL_MODE_RCV) { > + thr_run_func = gen_recv_thread; > + } else { > + ODP_ERR("ERR MODE\n"); > + exit(EXIT_FAILURE); > + } > + /* > + * Create threads one-by-one instead of all-at-once, > + * because each thread might get different arguments. > + * Calls odp_thread_create(cpu) for each thread > + */ > + odp_linux_pthread_create(thread_tbl, 1, > + core, thr_run_func, > + &args->thread[i]); > + } > + } > + > + /* Master thread waits for other threads to exit */ > + odp_linux_pthread_join(thread_tbl, num_workers); > + printf("Exit\n\n"); > + > + return 0; > +} > + > + > +/** > + * Parse and store the command line arguments > + * > + * @param argc argument count > + * @param argv[] argument vector > + * @param appl_args Store application arguments here > + */ > +static void parse_args(int argc, char *argv[], appl_args_t *appl_args) > +{ > + int opt; > + int long_index; > + char *names, *str, *token, *save; > + size_t len; > + int i; > + static struct option longopts[] = { > + {"interface", required_argument, NULL, 'I'}, > + {"workers", required_argument, NULL, 'w'}, > + {"srcmac", required_argument, NULL, 'a'}, > + {"dstmac", required_argument, NULL, 'b'}, > + {"srcip", required_argument, NULL, 'c'}, > + {"dstip", required_argument, NULL, 'd'}, > + {"packetsize", required_argument, NULL, 's'}, > + {"mode", required_argument, NULL, 'm'}, > + {"count", required_argument, NULL, 'n'}, > + {"timeout", required_argument, NULL, 't'}, > + {"interval", required_argument, NULL, 'i'}, > + {"help", no_argument, NULL, 'h'}, > + {NULL, 0, NULL, 0} > + }; > + > + appl_args->mode = -1; /* Invalid, must be changed by parsing */ > + appl_args->number = -1; > + appl_args->payload = 56; > + appl_args->timeout = -1; > + > + while (1) { > + opt = getopt_long(argc, argv, "+I:a:b:c:d:s:i:m:n:t:w:h", > + longopts, &long_index); > + if (opt == -1) > + break; /* No more options */ > + > + switch (opt) { > + case 'w': > + appl_args->core_count = atoi(optarg); > + break; > + /* parse packet-io interface names */ > + case 'I': > + len = strlen(optarg); > + if (len == 0) { > + usage(argv[0]); > + exit(EXIT_FAILURE); > + } > + len += 1; /* add room for '\0' */ > + > + names = malloc(len); > + if (names == NULL) { > + usage(argv[0]); > + exit(EXIT_FAILURE); > + } > + > + /* count the number of tokens separated by ',' */ > + strcpy(names, optarg); > + for (str = names, i = 0;; str = NULL, i++) { > + token = strtok_r(str, ",", &save); > + if (token == NULL) > + break; > + } > + appl_args->if_count = i; > + > + if (appl_args->if_count == 0) { > + usage(argv[0]); > + exit(EXIT_FAILURE); > + } > + > + /* allocate storage for the if names */ > + appl_args->if_names = > + calloc(appl_args->if_count, sizeof(char *)); > + > + /* store the if names (reset names string) */ > + strcpy(names, optarg); > + for (str = names, i = 0;; str = NULL, i++) { > + token = strtok_r(str, ",", &save); > + if (token == NULL) > + break; > + appl_args->if_names[i] = token; > + } > + break; > + > + case 'm': > + if (optarg[0] == 'u') { > + appl_args->mode = APPL_MODE_UDP; > + } else if (optarg[0] == 'p') { > + appl_args->mode = APPL_MODE_PING; > + } else if (optarg[0] == 'r') { > + appl_args->mode = APPL_MODE_RCV; > + } else { > + ODP_ERR("wrong mode!\n"); > + exit(EXIT_FAILURE); > + } > + break; > + > + case 'a': > + if (scan_mac(optarg, &appl_args->srcmac) != 1) { > + ODP_ERR("wrong src mac:%s\n", optarg); > + exit(EXIT_FAILURE); > + } > + break; > + > + case 'b': > + if (scan_mac(optarg, &appl_args->dstmac) != 1) { > + ODP_ERR("wrong dst mac:%s\n", optarg); > + exit(EXIT_FAILURE); > + } > + break; > + > + case 'c': > + if (scan_ip(optarg, &appl_args->srcip) != 1) { > + ODP_ERR("wrong src ip:%s\n", optarg); > + exit(EXIT_FAILURE); > + } > + break; > + > + case 'd': > + if (scan_ip(optarg, &appl_args->dstip) != 1) { > + ODP_ERR("wrong dst ip:%s\n", optarg); > + exit(EXIT_FAILURE); > + } > + break; > + > + case 's': > + appl_args->payload = atoi(optarg); > + break; > + > + case 'n': > + appl_args->number = atoi(optarg); > + break; > + > + case 't': > + appl_args->timeout = atoi(optarg); > + break; > + > + case 'i': > + appl_args->interval = atoi(optarg); > + if (appl_args->interval <= 200 && geteuid() != 0) { > + ODP_ERR("should be root user\n"); > + exit(EXIT_FAILURE); > + } > + break; > + > + case 'h': > + usage(argv[0]); > + exit(EXIT_SUCCESS); > + break; > + > + default: > + break; > + } > + } > + > + if (appl_args->if_count == 0 || appl_args->mode == -1) { > + usage(argv[0]); > + exit(EXIT_FAILURE); > + } > + > + optind = 1; /* reset 'extern optind' from the getopt lib */ > +} > + > +/** > + * Print system and application info > + */ > +static void print_info(char *progname, appl_args_t *appl_args) > +{ > + int i; > + > + printf("\n" > + "ODP system info\n" > + "---------------\n" > + "ODP API version: %s\n" > + "CPU model: %s\n" > + "CPU freq (hz): %"PRIu64"\n" > + "Cache line size: %i\n" > + "Core count: %i\n" > + "\n", > + odp_version_api_str(), odp_sys_cpu_model_str(), odp_sys_cpu_hz(), > + odp_sys_cache_line_size(), odp_sys_core_count()); > + > + printf("Running ODP appl: \"%s\"\n" > + "-----------------\n" > + "IF-count: %i\n" > + "Using IFs: ", > + progname, appl_args->if_count); > + for (i = 0; i < appl_args->if_count; ++i) > + printf(" %s", appl_args->if_names[i]); > + printf("\n" > + "Mode: "); > + if (appl_args->mode == 0) > + PRINT_APPL_MODE(0); > + else > + PRINT_APPL_MODE(0); > + printf("\n\n"); > + fflush(NULL); > +} > + > +/** > + * Prinf usage information > + */ > +static void usage(char *progname) > +{ > + printf("\n" > + "Usage: %s OPTIONS\n" > + " E.g. %s -I eth1 -r\n" > + "\n" > + "OpenDataPlane example application.\n" > + "\n" > + " Work mode:\n" > + " 1.send udp packets\n" > + " odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 --dstmac 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m u\n" > + " 2.receive udp packets\n" > + " odp_generator -I eth0 -m r\n" > + " 3.work likes ping\n" > + " odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 --dstmac 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m p\n" > + "\n" > + "Mandatory OPTIONS:\n" > + " -I, --interface Eth interfaces (comma-separated, no spaces)\n" > + " -a, --srcmac src mac address\n" > + " -b, --dstmac dst mac address\n" > + " -c, --srcip src ip address\n" > + " -d, --dstip dst ip address\n" > + " -s, --packetsize payload length of the packets\n" > + " -m, --mode work mode: send udp(u), receive(r), send icmp(p)\n" > + " -n, --count the number of packets to be send\n" > + " -t, --timeout only for ping mode, wait ICMP reply timeout seconds\n" > + " -i, --interval wait interval ms between sending each packet\n" > + " default is 1000ms. 0 for flood mode\n" > + "\n" > + "Optional OPTIONS\n" > + " -h, --help Display help and exit.\n" > + "\n", NO_PATH(progname), NO_PATH(progname) > + ); > +} > +/** > + * calc time period > + * > + *@param recvtime start time > + *@param sendtime end time > +*/ > +void tv_sub(struct timeval *recvtime, struct timeval *sendtime) > +{ > + long sec = recvtime->tv_sec - sendtime->tv_sec; > + long usec = recvtime->tv_usec - sendtime->tv_usec; > + if (usec >= 0) { > + recvtime->tv_sec = sec; > + recvtime->tv_usec = usec; > + } else { > + recvtime->tv_sec = sec - 1; > + recvtime->tv_usec = -usec; > + } > +}
OK, Fixed. On 5 May 2014 17:18, Maxim Uvarov <maxim.uvarov@linaro.org> wrote: > Compiling odp_generator.c > armeb-linux-gnueabihf-gcc -c -MD -DODP_DEBUG=1 -O3 -pthread -W -Wall > -Werror -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations > -Wold-style-definition -Wpointer-arith -Wcast-align -Wnested-externs > -Wcast-qual -Wformat-nonliteral -Wformat-security -Wundef -Wwrite-strings > -I/opt/LINARO/ODPrelease/ReleaseCommit2/odp2.git/build/include > -I/opt/LINARO/ODPrelease/ReleaseCommit2/odp2.git/build/include/api -o > obj/odp_generator.o odp_generator.c > In file included from odp_generator.c:25:0: > /opt/LINARO/ODPrelease/ReleaseCommit2/odp2.git/build/include/helper/odp_udp.h: > In function 'odp_ipv4_udp_chksum': > /opt/LINARO/ODPrelease/ReleaseCommit2/odp2.git/build/include/helper/odp_udp.h:61:8: > error: cast increases required alignment of target type [-Werror=cast-align] > buf = (unsigned short *)udph; > ^ > odp_generator.c: In function 'pack_icmp_pkt': > odp_generator.c:270:9: error: cast increases required alignment of target > type [-Werror=cast-align] > > tval = (struct timeval *)(buf + ODP_ETHHDR_LEN + ODP_IPV4HDR_LEN + > ^ > odp_generator.c:276:28: error: cast increases required alignment of target > type [-Werror=cast-align] > > icmp->chksum = odp_chksum((unsigned short *)icmp, args->appl.payload + > ^ > odp_generator.c: In function 'gen_send_thread': > odp_generator.c:339:11: error: format '%lu' expects argument of type 'long > unsigned int', but argument 3 has type 'odp_atomic_u64_t' [-Werror=format=] > thr, counters.seq, counters.seq%0xffff); > ^ > odp_generator.c:339:11: error: format '%lu' expects argument of type 'long > unsigned int', but argument 4 has type 'long long unsigned int' > [-Werror=format=] > odp_generator.c:346:11: error: format '%lu' expects argument of type 'long > unsigned int', but argument 3 has type 'odp_atomic_u64_t' [-Werror=format=] > thr, counters.seq, counters.seq%0xffff); > ^ > odp_generator.c:346:11: error: format '%lu' expects argument of type 'long > unsigned int', but argument 4 has type 'long long unsigned int' > [-Werror=format=] > odp_generator.c:367:3: error: format '%lu' expects argument of type 'long > unsigned int', but argument 3 has type 'odp_atomic_u64_t' [-Werror=format=] > > printf(" [%02i] total send:%lu\n", thr, counters.seq); > ^ > odp_generator.c:370:10: error: format '%lu' expects argument of type 'long > unsigned int', but argument 3 has type 'odp_atomic_u64_t' [-Werror=format=] > thr, counters.seq, counters.icmp); > ^ > odp_generator.c:370:10: error: format '%lu' expects argument of type 'long > unsigned int', but argument 4 has type 'odp_atomic_u64_t' [-Werror=format=] > odp_generator.c: In function 'print_pkts': > odp_generator.c:427:14: error: cast increases required alignment of target > type [-Werror=cast-align] > > tvsend = (struct timeval *)(buf + offset + > ^ > cc1: all warnings being treated as errors > > > > On 04/29/2014 01:03 PM, Weilong Chen wrote: > >> odp_generator can send/receive udp packets, or works like ping. >> Work mode: >> 1.send udp packets >> odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 --dstmac >> 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m u >> 2.receive udp packets >> odp_generator -I eth0 -m r >> 3.work likes ping >> odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 --dstmac >> 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m p >> >> Mandatory OPTIONS: >> -I, --interface Eth interfaces (comma-separated, no spaces) >> -a, --srcmac src mac address >> -b, --dstmac dst mac address >> -c, --srcip src ip address >> -d, --dstip dst ip address >> -s, --packetsize payload length of the packets >> -m, --mode work mode: send udp(u), receive(r), send icmp(p) >> -n, --count the number of packets to be send >> -t, --timeout only for ping mode, wait ICMP reply timeout seconds >> -i, --interval wait interval ms between sending each packet >> default is 1000ms. 0 for flood mode >> >> Signed-off-by: Weilong Chen <weilong.chen@linaro.org> >> --- >> .gitignore | 1 + >> test/Makefile | 3 + >> test/generator/Makefile | 46 ++ >> test/generator/odp_generator.c | 921 ++++++++++++++++++++++++++++++ >> ++++++++++ >> 4 files changed, 971 insertions(+) >> create mode 100644 test/generator/Makefile >> create mode 100644 test/generator/odp_generator.c >> >> diff --git a/.gitignore b/.gitignore >> index 781932c..b4c7017 100644 >> --- a/.gitignore >> +++ b/.gitignore >> @@ -16,3 +16,4 @@ test/api_test/odp_shm >> test/api_test/odp_ring >> test/api_test/odp_timer >> test/timer/odp_timer_test >> +test/generator/odp_generator >> diff --git a/test/Makefile b/test/Makefile >> index 9e3c482..cc3f4e9 100644 >> --- a/test/Makefile >> +++ b/test/Makefile >> @@ -10,6 +10,7 @@ all: >> $(MAKE) -C packet >> $(MAKE) -C packet_netmap >> $(MAKE) -C timer >> + $(MAKE) -C generator >> .PHONY: clean >> clean: >> @@ -18,6 +19,7 @@ clean: >> $(MAKE) -C packet clean >> $(MAKE) -C packet_netmap clean >> $(MAKE) -C timer clean >> + $(MAKE) -C generator clean >> .PHONY: install >> install: >> @@ -26,3 +28,4 @@ install: >> $(MAKE) -C packet install >> $(MAKE) -C packet_netmap install >> $(MAKE) -C timer install >> + $(MAKE) -C generator install >> diff --git a/test/generator/Makefile b/test/generator/Makefile >> new file mode 100644 >> index 0000000..d1f288d >> --- /dev/null >> +++ b/test/generator/Makefile >> @@ -0,0 +1,46 @@ >> +# Copyright (c) 2014, Linaro Limited >> +# All rights reserved. >> +# >> +# SPDX-License-Identifier: BSD-3-Clause >> + >> +ODP_ROOT = ../.. >> +ODP_APP = odp_generator >> + >> +include $(ODP_ROOT)/Makefile.inc >> +include ../Makefile.inc >> + >> +.PHONY: default >> +default: $(OBJ_DIR) $(ODP_APP) >> + >> +OBJS = >> +OBJS += $(OBJ_DIR)/odp_generator.o >> + >> +DEPS = $(OBJS:.o=.d) >> + >> +-include $(DEPS) >> + >> + >> +# >> +# Compile rules >> +# >> +$(OBJ_DIR)/%.o: %.c >> + $(ECHO) Compiling $< >> + $(CC) -c -MD $(EXTRA_CFLAGS) $(CFLAGS) -o $@ $< >> + >> +# >> +# Link rule >> +# >> +$(ODP_APP): $(ODP_LIB) $(OBJS) >> + $(ECHO) Linking $< >> + $(CC) $(LDFLAGS) $(OBJS) $(ODP_LIB) $(STD_LIBS) -o $@ >> + >> +.PHONY: clean >> +clean: >> + $(RMDIR) $(OBJ_DIR) >> + $(RM) $(ODP_APP) >> + $(MAKE) -C $(ODP_DIR) clean >> + >> +.PHONY: install >> +install: >> + install -d $(DESTDIR)/share/odp >> + install -m 0755 $(ODP_APP) $(DESTDIR)/share/odp/ >> diff --git a/test/generator/odp_generator.c b/test/generator/odp_ >> generator.c >> new file mode 100644 >> index 0000000..10b60ca >> --- /dev/null >> +++ b/test/generator/odp_generator.c >> @@ -0,0 +1,921 @@ >> +/* Copyright (c) 2014, Linaro Limited >> + * All rights reserved. >> + * >> + * SPDX-License-Identifier: BSD-3-Clause >> + */ >> + >> +/** >> + * @file >> + * >> + * @example odp_generator.c ODP loopback demo application >> + */ >> + >> +#include <stdlib.h> >> +#include <string.h> >> +#include <getopt.h> >> +#include <unistd.h> >> +#include <sys/time.h> >> + >> +#include <odp.h> >> +#include <odp_packet_io.h> >> +#include <helper/odp_linux.h> >> +#include <helper/odp_packet_helper.h> >> +#include <helper/odp_eth.h> >> +#include <helper/odp_ip.h> >> +#include <helper/odp_udp.h> >> +#include <helper/odp_icmp.h> >> + >> +#define MAX_WORKERS 32 /**< max number of works >> */ >> +#define SHM_PKT_POOL_SIZE (512*2048) /**< pkt pool size */ >> +#define SHM_PKT_POOL_BUF_SIZE 1856 /**< pkt pool buf size */ >> + >> +#define APPL_MODE_UDP 0 /**< UDP mode */ >> +#define APPL_MODE_PING 1 /**< ping mode */ >> +#define APPL_MODE_RCV 2 /**< receive mode */ >> + >> +/** print appl mode */ >> +#define PRINT_APPL_MODE(x) printf("%s(%i)\n", #x, (x)) >> + >> +/** Get rid of path in filename - only for unix-type paths using '/' */ >> +#define NO_PATH(file_name) (strrchr((file_name), '/') ? \ >> + strrchr((file_name), '/') + 1 : (file_name)) >> +/** >> + * Parsed command line application arguments >> + */ >> +typedef struct { >> + int core_count; /**< system core count */ >> + int if_count; /**< Number of interfaces to be used */ >> + char **if_names; /**< Array of pointers to interface names >> */ >> + odp_buffer_pool_t pool; /**< Buffer pool for packet IO */ >> + odp_ethaddr_t srcmac; /**< src mac addr */ >> + odp_ethaddr_t dstmac; /**< dest mac addr */ >> + unsigned int srcip; /**< src ip addr */ >> + unsigned int dstip; /**< dest ip addr */ >> + int mode; /**< work mode */ >> + int number; /**< packets number to be sent */ >> + int payload; /**< data len */ >> + int timeout; /**< wait time */ >> + int interval; /**< wait interval ms between sending >> each packet */ >> +} appl_args_t; >> + >> +/** >> + * counters >> +*/ >> +struct { >> + odp_atomic_u64_t seq; /**< ip seq to be send */ >> + odp_atomic_u64_t ip; /**< ip packets */ >> + odp_atomic_u64_t udp; /**< udp packets */ >> + odp_atomic_u64_t icmp; /**< icmp packets */ >> +} counters; >> + >> +/** * Thread specific arguments >> + */ >> +typedef struct { >> + char *pktio_dev; /**< Interface name to use */ >> + odp_buffer_pool_t pool; /**< Buffer pool for packet IO */ >> + int mode; /**< Thread mode */ >> +} thread_args_t; >> + >> +/** >> + * Grouping of both parsed CL args and thread specific args - alloc >> together >> + */ >> +typedef struct { >> + /** Application (parsed) arguments */ >> + appl_args_t appl; >> + /** Thread specific arguments */ >> + thread_args_t thread[MAX_WORKERS]; >> +} args_t; >> + >> +/** Global pointer to args */ >> +static args_t *args; >> + >> +/* helper funcs */ >> +static void parse_args(int argc, char *argv[], appl_args_t *appl_args); >> +static void print_info(char *progname, appl_args_t *appl_args); >> +static void usage(char *progname); >> +static int scan_ip(char *buf, unsigned int *paddr); >> +static int scan_mac(char *in, odp_ethaddr_t *des); >> +static void tv_sub(struct timeval *recvtime, struct timeval *sendtime); >> + >> +/** >> + * Scan ip >> + * Parse ip address. >> + * >> + * @param buf ip address string xxx.xxx.xxx.xx >> + * @param paddr ip address for odp_packet >> + * @return 1 success, 0 failed >> +*/ >> +int scan_ip(char *buf, unsigned int *paddr) >> +{ >> + int part1, part2, part3, part4; >> + char tail = 0; >> + int field; >> + >> + if (buf == NULL) >> + return 0; >> + >> + field = sscanf(buf, "%d . %d . %d . %d %c", >> + &part1, &part2, &part3, &part4, &tail); >> + >> + if (field < 4 || field > 5) { >> + printf("expect 4 field,get %d/n", field); >> + return 0; >> + } >> + >> + if (tail != 0) { >> + printf("ip address mixed with non number/n"); >> + return 0; >> + } >> + >> + if ((part1 >= 0 && part1 <= 255) && (part2 >= 0 && part2 <= 255) >> && >> + (part3 >= 0 && part3 <= 255) && (part4 >= 0 && part4 <= 255)) >> { >> + if (paddr) >> + *paddr = part1 << 24 | part2 << 16 | part3 << 8 | >> part4; >> + return 1; >> + } else { >> + printf("not good ip %d:%d:%d:%d/n", part1, part2, part3, >> part4); >> + } >> + >> + return 0; >> +} >> + >> +/** >> + * Scan mac addr form string >> + * >> + * @param in mac string >> + * @param des mac for odp_packet >> + * @return 1 success, 0 failed >> + */ >> +int scan_mac(char *in, odp_ethaddr_t *des) >> +{ >> + int field; >> + int i; >> + unsigned int mac[7]; >> + >> + field = sscanf(in, "%2x:%2x:%2x:%2x:%2x:%2x", >> + &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], >> &mac[5]); >> + >> + for (i = 0; i < 6; i++) >> + des->addr[i] = mac[i]; >> + >> + if (field != 6) >> + return 0; >> + return 1; >> +} >> + >> +/** >> + * set up an udp packet >> + * >> + * @param obuf packet buffer >> +*/ >> +static void pack_udp_pkt(odp_buffer_t obuf) >> +{ >> + char *buf; >> + int max; >> + odp_packet_t pkt; >> + odp_ethhdr_t *eth; >> + odp_ipv4hdr_t *ip; >> + odp_udphdr_t *udp; >> + unsigned short seq; >> + >> + buf = odp_buffer_addr(obuf); >> + if (buf == NULL) >> + return; >> + max = odp_buffer_size(obuf); >> + if (max <= 0) >> + return; >> + >> + pkt = odp_packet_from_buffer(obuf); >> + /* ether */ >> + odp_packet_set_l2_offset(pkt, 0); >> + eth = (odp_ethhdr_t *)buf; >> + memcpy((char *)eth->src.addr, args->appl.srcmac.addr, >> ODP_ETHADDR_LEN); >> + memcpy((char *)eth->dst.addr, args->appl.dstmac.addr, >> ODP_ETHADDR_LEN); >> + eth->type = odp_cpu_to_be_16(ODP_ETHTYPE_IPV4); >> + /* ip */ >> + odp_packet_set_l3_offset(pkt, ODP_ETHHDR_LEN); >> + ip = (odp_ipv4hdr_t *)(buf + ODP_ETHHDR_LEN); >> + ip->dst_addr = odp_cpu_to_be_32(args->appl.dstip); >> + ip->src_addr = odp_cpu_to_be_32(args->appl.srcip); >> + ip->ver_ihl = ODP_IPV4 << 4 | ODP_IPV4HDR_IHL_MIN; >> + ip->tot_len = odp_cpu_to_be_16(args->appl.payload + >> ODP_UDPHDR_LEN + >> + ODP_IPV4HDR_LEN); >> + ip->proto = ODP_IPPROTO_UDP; >> + seq = odp_atomic_fetch_add_u64(&counters.seq, 1) % 0xFFFF; >> + ip->id = odp_cpu_to_be_16(seq); >> + ip->chksum = 0; >> + odp_ipv4_csum_update(pkt); >> + /* udp */ >> + odp_packet_set_l4_offset(pkt, ODP_ETHHDR_LEN + ODP_IPV4HDR_LEN); >> + udp = (odp_udphdr_t *)(buf + ODP_ETHHDR_LEN + ODP_IPV4HDR_LEN); >> + udp->src_port = 0; >> + udp->dst_port = 0; >> + udp->length = odp_cpu_to_be_16(args->appl.payload + >> ODP_UDPHDR_LEN); >> + udp->chksum = 0; >> + udp->chksum = odp_ipv4_udp_chksum(pkt); >> + odp_packet_set_len(pkt, args->appl.payload + ODP_UDPHDR_LEN + >> + ODP_IPV4HDR_LEN + ODP_ETHHDR_LEN); >> +} >> + >> +/** >> + * Set up an icmp packet >> + * >> + * @param obuf packet buffer >> +*/ >> +static void pack_icmp_pkt(odp_buffer_t obuf) >> +{ >> + char *buf; >> + int max; >> + odp_packet_t pkt; >> + odp_ethhdr_t *eth; >> + odp_ipv4hdr_t *ip; >> + odp_icmphdr_t *icmp; >> + struct timeval *tval; >> + unsigned short seq; >> + >> + buf = odp_buffer_addr(obuf); >> + if (buf == NULL) >> + return; >> + max = odp_buffer_size(obuf); >> + if (max <= 0) >> + return; >> + >> + args->appl.payload = 56; >> + pkt = odp_packet_from_buffer(obuf); >> + /* ether */ >> + odp_packet_set_l2_offset(pkt, 0); >> + eth = (odp_ethhdr_t *)buf; >> + memcpy((char *)eth->src.addr, args->appl.srcmac.addr, >> ODP_ETHADDR_LEN); >> + memcpy((char *)eth->dst.addr, args->appl.dstmac.addr, >> ODP_ETHADDR_LEN); >> + eth->type = odp_cpu_to_be_16(ODP_ETHTYPE_IPV4); >> + /* ip */ >> + odp_packet_set_l3_offset(pkt, ODP_ETHHDR_LEN); >> + ip = (odp_ipv4hdr_t *)(buf + ODP_ETHHDR_LEN); >> + ip->dst_addr = odp_cpu_to_be_32(args->appl.dstip); >> + ip->src_addr = odp_cpu_to_be_32(args->appl.srcip); >> + ip->ver_ihl = ODP_IPV4 << 4 | ODP_IPV4HDR_IHL_MIN; >> + ip->tot_len = odp_cpu_to_be_16(args->appl.payload + >> ODP_ICMPHDR_LEN + >> + ODP_IPV4HDR_LEN); >> + ip->proto = ODP_IPPROTO_ICMP; >> + seq = odp_atomic_fetch_add_u64(&counters.seq, 1) % 0xffff; >> + ip->id = odp_cpu_to_be_16(seq); >> + ip->chksum = 0; >> + odp_ipv4_csum_update(pkt); >> + /* icmp */ >> + icmp = (odp_icmphdr_t *)(buf + ODP_ETHHDR_LEN + ODP_IPV4HDR_LEN); >> + icmp->type = ICMP_ECHO; >> + icmp->code = 0; >> + icmp->un.echo.id = 0; >> + icmp->un.echo.sequence = ip->id; >> + tval = (struct timeval *)(buf + ODP_ETHHDR_LEN + ODP_IPV4HDR_LEN + >> + ODP_ICMPHDR_LEN); >> + /* TODO This should be changed to use an >> + * ODP timer API once one exists. */ >> + gettimeofday(tval, NULL); >> + icmp->chksum = 0; >> + icmp->chksum = odp_chksum((unsigned short *)icmp, >> args->appl.payload + >> + ODP_ICMPHDR_LEN); >> + >> + odp_packet_set_len(pkt, args->appl.payload + ODP_ICMPHDR_LEN + >> + ODP_IPV4HDR_LEN + ODP_ETHHDR_LEN); >> +} >> + >> +/** >> + * Packet IO loopback worker thread using ODP queues >> + * >> + * @param arg thread arguments of type 'thread_args_t *' >> + */ >> + >> +static void *gen_send_thread(void *arg) >> +{ >> + int thr; >> + odp_pktio_t pktio; >> + thread_args_t *thr_args; >> + odp_queue_t outq_def; >> + odp_pktio_params_t params; >> + socket_params_t *sock_params = ¶ms.sock_params; >> + >> + odp_buffer_t buf; >> + >> + thr = odp_thread_id(); >> + thr_args = arg; >> + >> + /* Open a packet IO instance for this thread */ >> + sock_params->type = 1; >> + pktio = odp_pktio_open(thr_args->pktio_dev, thr_args->pool, >> ¶ms); >> + if (pktio == ODP_PKTIO_INVALID) { >> + ODP_ERR(" [%02i] Error: pktio create failed\n", thr); >> + return NULL; >> + } >> + >> + outq_def = odp_pktio_outq_getdef(pktio); >> + if (outq_def == ODP_QUEUE_INVALID) { >> + ODP_ERR(" [%02i] Error: def output-Q query\n", thr); >> + return NULL; >> + } >> + >> + printf(" [%02i] created mode: SEND\n", thr); >> + for (;;) { >> + int err; >> + buf = odp_buffer_alloc(thr_args->pool); >> + if (!odp_buffer_is_valid(buf)) { >> + ODP_ERR(" [%2i] alloc_single failed\n", thr); >> + return NULL; >> + } >> + >> + if (args->appl.mode == APPL_MODE_UDP) >> + pack_udp_pkt(buf); >> + else if (args->appl.mode == APPL_MODE_PING) >> + pack_icmp_pkt(buf); >> + >> + err = odp_queue_enq(outq_def, buf); >> + if (err != 0) { >> + ODP_ERR(" [%02i] send pkt err!\n", thr); >> + return NULL; >> + } >> + >> + if (args->appl.interval != 0) { >> + printf(" [%02i] send pkt no:%lu seq %lu\n", >> + thr, counters.seq, counters.seq%0xffff); >> + /* TODO use odp timer */ >> + usleep(args->appl.interval * 1000); >> + } else { >> + /* TODO maybe need a rating control */ >> + /* flood mode use '\r' instead of '\n' */ >> + printf(" [%02i] send pkt no:%lu seq %lu\r", >> + thr, counters.seq, counters.seq%0xffff); >> + } >> + if (args->appl.number != -1 && counters.seq >> + >= (unsigned int)args->appl.number) { >> + break; >> + } >> + } >> + >> + /* receive number of reply pks until timeout */ >> + if (args->appl.mode == APPL_MODE_PING && args->appl.number > 0) { >> + while (args->appl.timeout >= 0) { >> + if (counters.icmp >= (unsigned >> int)args->appl.number) >> + break; >> + /* TODO use odp timer */ >> + sleep(1); >> + args->appl.timeout--; >> + } >> + } >> + >> + /* print info */ >> + if (args->appl.mode == APPL_MODE_UDP) { >> + printf(" [%02i] total send:%lu\n", thr, counters.seq); >> + } else if (args->appl.mode == APPL_MODE_PING) { >> + printf(" [%02i] total send:%lu,total receiver %lu\n", >> + thr, counters.seq, counters.icmp); >> + } >> + return arg; >> +} >> + >> +/** >> + * Print odp packets >> + * >> + * @param thr worker id >> + * @param pkt_tbl packets to be print >> + * @param len packet number >> + */ >> +static void print_pkts(int thr, odp_packet_t pkt_tbl[], unsigned len) >> +{ >> + odp_packet_t pkt; >> + char *buf; >> + odp_ipv4hdr_t *ip; >> + odp_udphdr_t *udp; >> + odp_icmphdr_t *icmp; >> + struct timeval tvrecv; >> + struct timeval *tvsend; >> + double rtt; >> + unsigned i; >> + size_t offset; >> + char msg[1024]; >> + int rlen; >> + for (i = 0; i < len; ++i) { >> + pkt = pkt_tbl[i]; >> + rlen = 0; >> + >> + /* only ip pkts */ >> + if (!odp_packet_inflag_ipv4(pkt)) >> + continue; >> + >> + odp_atomic_inc_u64(&counters.ip); >> + rlen += sprintf(msg, "receive Packet proto:IP "); >> + buf = odp_buffer_addr(odp_buffer_from_packet(pkt)); >> + ip = (odp_ipv4hdr_t *)(buf + odp_packet_l3_offset(pkt)); >> + rlen += sprintf(msg + rlen, "id %d ", >> + odp_be_to_cpu_16(ip->id)); >> + offset = odp_packet_l4_offset(pkt); >> + >> + /* udp */ >> + if (ip->proto == ODP_IPPROTO_UDP) { >> + odp_atomic_inc_u64(&counters.udp); >> + udp = (odp_udphdr_t *)(buf + offset); >> + rlen += sprintf(msg + rlen, "UDP payload %d ", >> + odp_be_to_cpu_16(udp->length) - >> + ODP_UDPHDR_LEN); >> + } >> + >> + /* icmp */ >> + if (ip->proto == ODP_IPPROTO_ICMP) { >> + icmp = (odp_icmphdr_t *)(buf + offset); >> + /* echo reply */ >> + if (icmp->type == ICMP_ECHOREPLY) { >> + odp_atomic_inc_u64(&counters.icmp); >> + tvsend = (struct timeval *)(buf + offset + >> + >> ODP_ICMPHDR_LEN); >> + /* TODO This should be changed to use an >> + * ODP timer API once one exists. */ >> + gettimeofday(&tvrecv, NULL); >> + tv_sub(&tvrecv, tvsend); >> + rtt = tvrecv.tv_sec*1000 + >> tvrecv.tv_usec/1000; >> + rlen += sprintf(msg + rlen, >> + "ICMP Echo Reply seq %d time %.1f >> ", >> + odp_be_to_cpu_16(icmp->un. >> echo.sequence) >> + , rtt); >> + } else if (icmp->type == ICMP_ECHO) { >> + rlen += sprintf(msg + rlen, >> + "Icmp Echo Request"); >> + } >> + } >> + >> + msg[rlen] = '\0'; >> + printf(" [%02i] %s\n", thr, msg); >> + } >> +} >> + >> +/** >> + * Main receive funtion >> + * >> + * @param arg thread arguments of type 'thread_args_t *' >> + */ >> +static void *gen_recv_thread(void *arg) >> +{ >> + int thr; >> + odp_pktio_t pktio; >> + thread_args_t *thr_args; >> + odp_queue_t inq_def; >> + odp_pktio_params_t params; >> + char inq_name[ODP_QUEUE_NAME_LEN]; >> + odp_queue_param_t qparam; >> + socket_params_t *sock_params = ¶ms.sock_params; >> + >> + odp_packet_t pkt; >> + odp_buffer_t buf; >> + >> + thr = odp_thread_id(); >> + thr_args = arg; >> + >> + /* Open a packet IO instance for this thread */ >> + sock_params->type = 1; >> + pktio = odp_pktio_open(thr_args->pktio_dev, thr_args->pool, >> ¶ms); >> + if (pktio == ODP_PKTIO_INVALID) { >> + ODP_ERR(" [%02i] Error: pktio create failed\n", thr); >> + return NULL; >> + } >> + >> + int ret; >> + qparam.sched.prio = ODP_SCHED_PRIO_DEFAULT; >> + qparam.sched.sync = ODP_SCHED_SYNC_ATOMIC; >> + qparam.sched.group = ODP_SCHED_GROUP_DEFAULT; >> + snprintf(inq_name, sizeof(inq_name), "%i-pktio_inq_def", >> (int)pktio); >> + inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0'; >> + inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN, >> &qparam); >> + if (inq_def == ODP_QUEUE_INVALID) { >> + ODP_ERR(" [%02i] Error: pktio queue creation failed\n", >> thr); >> + return NULL; >> + } >> + >> + ret = odp_pktio_inq_setdef(pktio, inq_def); >> + if (ret != 0) { >> + ODP_ERR(" [%02i] Error: default input-Q setup\n", thr); >> + return NULL; >> + } >> + >> + printf(" [%02i] created mode: RECEIVE\n", thr); >> + for (;;) { >> + /* Use schedule to get buf from any input queue */ >> + buf = odp_schedule(NULL, ODP_SCHED_WAIT); >> + >> + pkt = odp_packet_from_buffer(buf); >> + /* Drop packets with errors */ >> + if (odp_unlikely(odp_packet_error(pkt))) { >> + odp_packet_free(pkt); >> + continue; >> + } >> + >> + print_pkts(thr, &pkt, 1); >> + >> + odp_packet_free(pkt); >> + } >> + >> + return arg; >> +} >> +/** >> + * ODP packet example main function >> + */ >> +int main(int argc, char *argv[]) >> +{ >> + odp_linux_pthread_t thread_tbl[MAX_WORKERS]; >> + odp_buffer_pool_t pool; >> + int thr_id; >> + int num_workers; >> + void *pool_base; >> + int i; >> + int first_core; >> + int core_count; >> + >> + /* Init ODP before calling anything else */ >> + if (odp_init_global()) { >> + ODP_ERR("Error: ODP global init failed.\n"); >> + exit(EXIT_FAILURE); >> + } >> + >> + /* init counters */ >> + odp_atomic_init_u64(&counters.seq); >> + odp_atomic_init_u64(&counters.ip); >> + odp_atomic_init_u64(&counters.udp); >> + odp_atomic_init_u64(&counters.icmp); >> + >> + /* Reserve memory for args from shared mem */ >> + args = odp_shm_reserve("shm_args", sizeof(args_t), >> ODP_CACHE_LINE_SIZE); >> + if (args == NULL) { >> + ODP_ERR("Error: shared mem alloc failed.\n"); >> + exit(EXIT_FAILURE); >> + } >> + memset(args, 0, sizeof(*args)); >> + >> + /* Parse and store the application arguments */ >> + parse_args(argc, argv, &args->appl); >> + >> + /* Print both system and application information */ >> + print_info(NO_PATH(argv[0]), &args->appl); >> + >> + core_count = odp_sys_core_count(); >> + num_workers = core_count; >> + >> + if (args->appl.core_count) >> + num_workers = args->appl.core_count; >> + >> + if (num_workers > MAX_WORKERS) >> + num_workers = MAX_WORKERS; >> + >> + /* ping mode need two worker */ >> + if (args->appl.mode == APPL_MODE_PING) >> + num_workers = 2; >> + >> + printf("Num worker threads: %i\n", num_workers); >> + >> + /* >> + * By default core #0 runs Linux kernel background tasks. >> + * Start mapping thread from core #1 >> + */ >> + first_core = 1; >> + >> + if (core_count == 1) >> + first_core = 0; >> + >> + printf("First core: %i\n\n", first_core); >> + >> + /* Init this thread */ >> + thr_id = odp_thread_create(0); >> + odp_init_local(thr_id); >> + >> + /* Create packet pool */ >> + pool_base = odp_shm_reserve("shm_packet_pool", >> + SHM_PKT_POOL_SIZE, >> ODP_CACHE_LINE_SIZE); >> + if (pool_base == NULL) { >> + ODP_ERR("Error: packet pool mem alloc failed.\n"); >> + exit(EXIT_FAILURE); >> + } >> + >> + pool = odp_buffer_pool_create("packet_pool", pool_base, >> + SHM_PKT_POOL_SIZE, >> + SHM_PKT_POOL_BUF_SIZE, >> + ODP_CACHE_LINE_SIZE, >> + ODP_BUFFER_TYPE_PACKET); >> + if (pool == ODP_BUFFER_POOL_INVALID) { >> + ODP_ERR("Error: packet pool create failed.\n"); >> + exit(EXIT_FAILURE); >> + } >> + odp_buffer_pool_print(pool); >> + >> + /* Create and init worker threads */ >> + memset(thread_tbl, 0, sizeof(thread_tbl)); >> + >> + if (args->appl.mode == APPL_MODE_PING) { >> + args->thread[1].pktio_dev = args->appl.if_names[0]; >> + args->thread[1].pool = pool; >> + args->thread[1].mode = args->appl.mode; >> + odp_linux_pthread_create(thread_tbl, 1, 0, >> + gen_recv_thread, >> &args->thread[1]); >> + >> + args->thread[0].pktio_dev = args->appl.if_names[0]; >> + args->thread[0].pool = pool; >> + args->thread[0].mode = args->appl.mode; >> + odp_linux_pthread_create(thread_tbl, 1, 0, >> + gen_send_thread, >> &args->thread[0]); >> + >> + /* only wait send thread to join */ >> + num_workers = 1; >> + } else { >> + for (i = 0; i < num_workers; ++i) { >> + void *(*thr_run_func) (void *); >> + int core; >> + int if_idx; >> + >> + core = (first_core + i) % core_count; >> + >> + if_idx = i % args->appl.if_count; >> + >> + args->thread[i].pktio_dev = >> args->appl.if_names[if_idx]; >> + args->thread[i].pool = pool; >> + args->thread[i].mode = args->appl.mode; >> + >> + if (args->appl.mode == APPL_MODE_UDP) { >> + thr_run_func = gen_send_thread; >> + } else if (args->appl.mode == APPL_MODE_RCV) { >> + thr_run_func = gen_recv_thread; >> + } else { >> + ODP_ERR("ERR MODE\n"); >> + exit(EXIT_FAILURE); >> + } >> + /* >> + * Create threads one-by-one instead of >> all-at-once, >> + * because each thread might get different >> arguments. >> + * Calls odp_thread_create(cpu) for each thread >> + */ >> + odp_linux_pthread_create(thread_tbl, 1, >> + core, thr_run_func, >> + &args->thread[i]); >> + } >> + } >> + >> + /* Master thread waits for other threads to exit */ >> + odp_linux_pthread_join(thread_tbl, num_workers); >> + printf("Exit\n\n"); >> + >> + return 0; >> +} >> + >> + >> +/** >> + * Parse and store the command line arguments >> + * >> + * @param argc argument count >> + * @param argv[] argument vector >> + * @param appl_args Store application arguments here >> + */ >> +static void parse_args(int argc, char *argv[], appl_args_t *appl_args) >> +{ >> + int opt; >> + int long_index; >> + char *names, *str, *token, *save; >> + size_t len; >> + int i; >> + static struct option longopts[] = { >> + {"interface", required_argument, NULL, 'I'}, >> + {"workers", required_argument, NULL, 'w'}, >> + {"srcmac", required_argument, NULL, 'a'}, >> + {"dstmac", required_argument, NULL, 'b'}, >> + {"srcip", required_argument, NULL, 'c'}, >> + {"dstip", required_argument, NULL, 'd'}, >> + {"packetsize", required_argument, NULL, 's'}, >> + {"mode", required_argument, NULL, 'm'}, >> + {"count", required_argument, NULL, 'n'}, >> + {"timeout", required_argument, NULL, 't'}, >> + {"interval", required_argument, NULL, 'i'}, >> + {"help", no_argument, NULL, 'h'}, >> + {NULL, 0, NULL, 0} >> + }; >> + >> + appl_args->mode = -1; /* Invalid, must be changed by parsing */ >> + appl_args->number = -1; >> + appl_args->payload = 56; >> + appl_args->timeout = -1; >> + >> + while (1) { >> + opt = getopt_long(argc, argv, "+I:a:b:c:d:s:i:m:n:t:w:h", >> + longopts, &long_index); >> + if (opt == -1) >> + break; /* No more options */ >> + >> + switch (opt) { >> + case 'w': >> + appl_args->core_count = atoi(optarg); >> + break; >> + /* parse packet-io interface names */ >> + case 'I': >> + len = strlen(optarg); >> + if (len == 0) { >> + usage(argv[0]); >> + exit(EXIT_FAILURE); >> + } >> + len += 1; /* add room for '\0' */ >> + >> + names = malloc(len); >> + if (names == NULL) { >> + usage(argv[0]); >> + exit(EXIT_FAILURE); >> + } >> + >> + /* count the number of tokens separated by ',' */ >> + strcpy(names, optarg); >> + for (str = names, i = 0;; str = NULL, i++) { >> + token = strtok_r(str, ",", &save); >> + if (token == NULL) >> + break; >> + } >> + appl_args->if_count = i; >> + >> + if (appl_args->if_count == 0) { >> + usage(argv[0]); >> + exit(EXIT_FAILURE); >> + } >> + >> + /* allocate storage for the if names */ >> + appl_args->if_names = >> + calloc(appl_args->if_count, sizeof(char *)); >> + >> + /* store the if names (reset names string) */ >> + strcpy(names, optarg); >> + for (str = names, i = 0;; str = NULL, i++) { >> + token = strtok_r(str, ",", &save); >> + if (token == NULL) >> + break; >> + appl_args->if_names[i] = token; >> + } >> + break; >> + >> + case 'm': >> + if (optarg[0] == 'u') { >> + appl_args->mode = APPL_MODE_UDP; >> + } else if (optarg[0] == 'p') { >> + appl_args->mode = APPL_MODE_PING; >> + } else if (optarg[0] == 'r') { >> + appl_args->mode = APPL_MODE_RCV; >> + } else { >> + ODP_ERR("wrong mode!\n"); >> + exit(EXIT_FAILURE); >> + } >> + break; >> + >> + case 'a': >> + if (scan_mac(optarg, &appl_args->srcmac) != 1) { >> + ODP_ERR("wrong src mac:%s\n", optarg); >> + exit(EXIT_FAILURE); >> + } >> + break; >> + >> + case 'b': >> + if (scan_mac(optarg, &appl_args->dstmac) != 1) { >> + ODP_ERR("wrong dst mac:%s\n", optarg); >> + exit(EXIT_FAILURE); >> + } >> + break; >> + >> + case 'c': >> + if (scan_ip(optarg, &appl_args->srcip) != 1) { >> + ODP_ERR("wrong src ip:%s\n", optarg); >> + exit(EXIT_FAILURE); >> + } >> + break; >> + >> + case 'd': >> + if (scan_ip(optarg, &appl_args->dstip) != 1) { >> + ODP_ERR("wrong dst ip:%s\n", optarg); >> + exit(EXIT_FAILURE); >> + } >> + break; >> + >> + case 's': >> + appl_args->payload = atoi(optarg); >> + break; >> + >> + case 'n': >> + appl_args->number = atoi(optarg); >> + break; >> + >> + case 't': >> + appl_args->timeout = atoi(optarg); >> + break; >> + >> + case 'i': >> + appl_args->interval = atoi(optarg); >> + if (appl_args->interval <= 200 && geteuid() != 0) >> { >> + ODP_ERR("should be root user\n"); >> + exit(EXIT_FAILURE); >> + } >> + break; >> + >> + case 'h': >> + usage(argv[0]); >> + exit(EXIT_SUCCESS); >> + break; >> + >> + default: >> + break; >> + } >> + } >> + >> + if (appl_args->if_count == 0 || appl_args->mode == -1) { >> + usage(argv[0]); >> + exit(EXIT_FAILURE); >> + } >> + >> + optind = 1; /* reset 'extern optind' from the getopt >> lib */ >> +} >> + >> +/** >> + * Print system and application info >> + */ >> +static void print_info(char *progname, appl_args_t *appl_args) >> +{ >> + int i; >> + >> + printf("\n" >> + "ODP system info\n" >> + "---------------\n" >> + "ODP API version: %s\n" >> + "CPU model: %s\n" >> + "CPU freq (hz): %"PRIu64"\n" >> + "Cache line size: %i\n" >> + "Core count: %i\n" >> + "\n", >> + odp_version_api_str(), odp_sys_cpu_model_str(), >> odp_sys_cpu_hz(), >> + odp_sys_cache_line_size(), odp_sys_core_count()); >> + >> + printf("Running ODP appl: \"%s\"\n" >> + "-----------------\n" >> + "IF-count: %i\n" >> + "Using IFs: ", >> + progname, appl_args->if_count); >> + for (i = 0; i < appl_args->if_count; ++i) >> + printf(" %s", appl_args->if_names[i]); >> + printf("\n" >> + "Mode: "); >> + if (appl_args->mode == 0) >> + PRINT_APPL_MODE(0); >> + else >> + PRINT_APPL_MODE(0); >> + printf("\n\n"); >> + fflush(NULL); >> +} >> + >> +/** >> + * Prinf usage information >> + */ >> +static void usage(char *progname) >> +{ >> + printf("\n" >> + "Usage: %s OPTIONS\n" >> + " E.g. %s -I eth1 -r\n" >> + "\n" >> + "OpenDataPlane example application.\n" >> + "\n" >> + " Work mode:\n" >> + " 1.send udp packets\n" >> + " odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 >> --dstmac 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m u\n" >> + " 2.receive udp packets\n" >> + " odp_generator -I eth0 -m r\n" >> + " 3.work likes ping\n" >> + " odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 >> --dstmac 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m p\n" >> + "\n" >> + "Mandatory OPTIONS:\n" >> + " -I, --interface Eth interfaces (comma-separated, no >> spaces)\n" >> + " -a, --srcmac src mac address\n" >> + " -b, --dstmac dst mac address\n" >> + " -c, --srcip src ip address\n" >> + " -d, --dstip dst ip address\n" >> + " -s, --packetsize payload length of the packets\n" >> + " -m, --mode work mode: send udp(u), receive(r), send >> icmp(p)\n" >> + " -n, --count the number of packets to be send\n" >> + " -t, --timeout only for ping mode, wait ICMP reply >> timeout seconds\n" >> + " -i, --interval wait interval ms between sending each >> packet\n" >> + " default is 1000ms. 0 for flood mode\n" >> + "\n" >> + "Optional OPTIONS\n" >> + " -h, --help Display help and exit.\n" >> + "\n", NO_PATH(progname), NO_PATH(progname) >> + ); >> +} >> +/** >> + * calc time period >> + * >> + *@param recvtime start time >> + *@param sendtime end time >> +*/ >> +void tv_sub(struct timeval *recvtime, struct timeval *sendtime) >> +{ >> + long sec = recvtime->tv_sec - sendtime->tv_sec; >> + long usec = recvtime->tv_usec - sendtime->tv_usec; >> + if (usec >= 0) { >> + recvtime->tv_sec = sec; >> + recvtime->tv_usec = usec; >> + } else { >> + recvtime->tv_sec = sec - 1; >> + recvtime->tv_usec = -usec; >> + } >> +} >> > > > _______________________________________________ > lng-odp mailing list > lng-odp@lists.linaro.org > http://lists.linaro.org/mailman/listinfo/lng-odp >
Hi Anders, How to compile with c99? When I tried to do that, I got those message: /linaro/odp# make CC=gcc CFLAGS="-std=c99" make -C /home/huawei/linaro/odp/platform/linux-generic libs make[1]: Entering directory `/home/huawei/linaro/odp/platform/linux-generic' Compiling source/odp_barrier.c gcc -c -MD -I../../include -I./include -I./include/api -DODP_DEBUG=1 -O3 -pthread -W -Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wold-style-definition -Wpointer-arith -Wcast-align -Wnested-externs -Wcast-qual -Wformat-nonliteral -Wformat-security -Wundef -Wwrite-strings -std=c99 -o obj/odp_barrier.o source/odp_barrier.c In file included from source/odp_barrier.c:9:0: ./include/odp_spin_internal.h: In function ‘odp_mem_barrier’: ./include/odp_spin_internal.h:22:2: error: ‘asm’ undeclared (first use in this function) ./include/odp_spin_internal.h:22:2: note: each undeclared identifier is reported only once for each function it appears in ./include/odp_spin_internal.h:22:6: error: expected ‘;’ before ‘__volatile__’ ./include/odp_spin_internal.h: In function ‘odp_spin’: ./include/odp_spin_internal.h:34:2: error: ‘asm’ undeclared (first use in this function) ./include/odp_spin_internal.h:34:6: error: expected ‘;’ before ‘__volatile__’ make[1]: *** [obj/odp_barrier.o] Error 1 make[1]: Leaving directory `/home/huawei/linaro/odp/platform/linux-generic' make: *** [lib] Error 2 Thanks, Weilong On 3 May 2014 07:34, Anders Roxell <anders.roxell@linaro.org> wrote: > On 2014-04-29 17:03, Weilong Chen wrote: > > odp_generator can send/receive udp packets, or works like ping. > > Work mode: > > 1.send udp packets > > odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 --dstmac > 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m u > > 2.receive udp packets > > odp_generator -I eth0 -m r > > 3.work likes ping > > odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 --dstmac > 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m p > > > > Mandatory OPTIONS: > > -I, --interface Eth interfaces (comma-separated, no spaces) > > -a, --srcmac src mac address > > -b, --dstmac dst mac address > > -c, --srcip src ip address > > -d, --dstip dst ip address > > -s, --packetsize payload length of the packets > > -m, --mode work mode: send udp(u), receive(r), send icmp(p) > > -n, --count the number of packets to be send > > -t, --timeout only for ping mode, wait ICMP reply timeout seconds > > -i, --interval wait interval ms between sending each packet > > default is 1000ms. 0 for flood mode > > > > Signed-off-by: Weilong Chen <weilong.chen@linaro.org> > > Couldn't build with -std=C99 > > $ make CC=gcc CFLAGS="-std=c99" > Compiling odp_generator.c > gcc -c -MD -DODP_DEBUG=1 -O3 -pthread -W -Wall -Werror -Ws > > trict-prototypes -Wmissing-prototypes -Wmissing-declarations > -Wold-style-definition -Wpointer-arith -Wcast-align -Wnested-externs > -Wcast-qual -Wformat-nonliteral -Wformat-security -Wundef -Wwrite-strings > -I../../include -I../../platform/linux-generic/include/api -std=c99 -o > obj/odp_generator.o odp_generator.c > odp_generator.c: In function ‘gen_send_thread’: > odp_generator.c:341:4: error: implicit declaration of function ‘usleep’ > [-Werror=implicit-function-declaration] > usleep(args->appl.interval * 1000); > ^ > odp_generator.c:341:4: error: nested extern declaration of ‘usleep’ > [-Werror=nested-externs] > odp_generator.c: In function ‘parse_args’: > odp_generator.c:727:5: error: implicit declaration of function ‘strtok_r’ > [-Werror=implicit-function-declaration] > token = strtok_r(str, ",", &save); > ^ > odp_generator.c:727:5: error: nested extern declaration of ‘strtok_r’ > [-Werror=nested-externs] > odp_generator.c:727:11: error: assignment makes pointer from integer > without a cast [-Werror] > token = strtok_r(str, ",", &save); > ^ > odp_generator.c:745:11: error: assignment makes pointer from integer > without a cast [-Werror] > token = strtok_r(str, ",", &save); > ^ > cc1: all warnings being treated as errors > make: *** [obj/odp_generator.o] Error 1 > > > Cheers, > Anders >
On 05/07/2014 01:16 PM, Weilong Chen wrote: > Hi Anders, > > How to compile with c99? it does not compile now with c99 because Anders send only half of patches which to make it c99. Some more work is needed there. I think it's better to apply all patch set for c99, so it's not critical now. Thanks, Maxim. > > When I tried to do that, I got those message: > > > /linaro/odp# make CC=gcc CFLAGS="-std=c99" > make -C /home/huawei/linaro/odp/platform/linux-generic libs > make[1]: Entering directory > `/home/huawei/linaro/odp/platform/linux-generic' > Compiling source/odp_barrier.c > gcc -c -MD -I../../include -I./include -I./include/api -DODP_DEBUG=1 > -O3 -pthread -W -Wall -Werror -Wstrict-prototypes -Wmissing-prototypes > -Wmissing-declarations -Wold-style-definition -Wpointer-arith > -Wcast-align -Wnested-externs -Wcast-qual -Wformat-nonliteral > -Wformat-security -Wundef -Wwrite-strings -std=c99 -o > obj/odp_barrier.o source/odp_barrier.c > In file included from source/odp_barrier.c:9:0: > ./include/odp_spin_internal.h: In function ‘odp_mem_barrier’: > ./include/odp_spin_internal.h:22:2: error: ‘asm’ undeclared (first use > in this function) > ./include/odp_spin_internal.h:22:2: note: each undeclared identifier > is reported only once for each function it appears in > ./include/odp_spin_internal.h:22:6: error: expected ‘;’ before > ‘__volatile__’ > ./include/odp_spin_internal.h: In function ‘odp_spin’: > ./include/odp_spin_internal.h:34:2: error: ‘asm’ undeclared (first use > in this function) > ./include/odp_spin_internal.h:34:6: error: expected ‘;’ before > ‘__volatile__’ > make[1]: *** [obj/odp_barrier.o] Error 1 > make[1]: Leaving directory > `/home/huawei/linaro/odp/platform/linux-generic' > make: *** [lib] Error 2 > > Thanks, > Weilong > > > On 3 May 2014 07:34, Anders Roxell <anders.roxell@linaro.org > <mailto:anders.roxell@linaro.org>> wrote: > > On 2014-04-29 17:03, Weilong Chen wrote: > > odp_generator can send/receive udp packets, or works like ping. > > Work mode: > > 1.send udp packets > > odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 --dstmac > 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m u > > 2.receive udp packets > > odp_generator -I eth0 -m r > > 3.work likes ping > > odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 --dstmac > 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m p > > > > Mandatory OPTIONS: > > -I, --interface Eth interfaces (comma-separated, no spaces) > > -a, --srcmac src mac address > > -b, --dstmac dst mac address > > -c, --srcip src ip address > > -d, --dstip dst ip address > > -s, --packetsize payload length of the packets > > -m, --mode work mode: send udp(u), receive(r), send icmp(p) > > -n, --count the number of packets to be send > > -t, --timeout only for ping mode, wait ICMP reply timeout seconds > > -i, --interval wait interval ms between sending each packet > > default is 1000ms. 0 for flood mode > > > > Signed-off-by: Weilong Chen <weilong.chen@linaro.org > <mailto:weilong.chen@linaro.org>> > > Couldn't build with -std=C99 > > $ make CC=gcc CFLAGS="-std=c99" > Compiling odp_generator.c > gcc -c -MD -DODP_DEBUG=1 -O3 -pthread -W -Wall -Werror -Ws > > trict-prototypes -Wmissing-prototypes -Wmissing-declarations > -Wold-style-definition -Wpointer-arith -Wcast-align > -Wnested-externs -Wcast-qual -Wformat-nonliteral -Wformat-security > -Wundef -Wwrite-strings -I../../include > -I../../platform/linux-generic/include/api -std=c99 -o > obj/odp_generator.o odp_generator.c > odp_generator.c: In function ‘gen_send_thread’: > odp_generator.c:341:4: error: implicit declaration of function > ‘usleep’ [-Werror=implicit-function-declaration] > usleep(args->appl.interval * 1000); > ^ > odp_generator.c:341:4: error: nested extern declaration of > ‘usleep’ [-Werror=nested-externs] > odp_generator.c: In function ‘parse_args’: > odp_generator.c:727:5: error: implicit declaration of function > ‘strtok_r’ [-Werror=implicit-function-declaration] > token = strtok_r(str, ",", &save); > ^ > odp_generator.c:727:5: error: nested extern declaration of > ‘strtok_r’ [-Werror=nested-externs] > odp_generator.c:727:11: error: assignment makes pointer from > integer without a cast [-Werror] > token = strtok_r(str, ",", &save); > ^ > odp_generator.c:745:11: error: assignment makes pointer from > integer without a cast [-Werror] > token = strtok_r(str, ",", &save); > ^ > cc1: all warnings being treated as errors > make: *** [obj/odp_generator.o] Error 1 > > > Cheers, > Anders > > > > > _______________________________________________ > lng-odp mailing list > lng-odp@lists.linaro.org > http://lists.linaro.org/mailman/listinfo/lng-odp
On 2014-05-07 14:42, Maxim Uvarov wrote: > On 05/07/2014 01:16 PM, Weilong Chen wrote: > >Hi Anders, > > > >How to compile with c99? To answer your question, I did: cd <odp root> make cd test/generator make CFLAGS="-std=c99" If you don't apply my 4 patches you will get some other errors as well... > > it does not compile now with c99 because Anders send only half of > patches which to make it c99. Some more work is needed there. > I think it's better to apply all patch set for c99, so it's not > critical now. I think we should apply my patch series that fixes some additional C99 problems. I can see that there is already one patch submitted and accepted that makes some code C99 friendly "37934f1 : make asm includes C99 standard friendly" We can apply this patch without enforcing that C99 is set. However, the moment we enforce -std=c99 you have to fix this patch anyway. Cheers, Anders > > Thanks, > Maxim. > > > >When I tried to do that, I got those message: > > > > > >/linaro/odp# make CC=gcc CFLAGS="-std=c99" > >make -C /home/huawei/linaro/odp/platform/linux-generic libs > >make[1]: Entering directory > >`/home/huawei/linaro/odp/platform/linux-generic' > >Compiling source/odp_barrier.c > >gcc -c -MD -I../../include -I./include -I./include/api > >-DODP_DEBUG=1 -O3 -pthread -W -Wall -Werror -Wstrict-prototypes > >-Wmissing-prototypes -Wmissing-declarations -Wold-style-definition > >-Wpointer-arith -Wcast-align -Wnested-externs -Wcast-qual > >-Wformat-nonliteral -Wformat-security -Wundef -Wwrite-strings > >-std=c99 -o obj/odp_barrier.o source/odp_barrier.c > >In file included from source/odp_barrier.c:9:0: > >./include/odp_spin_internal.h: In function ‘odp_mem_barrier’: > >./include/odp_spin_internal.h:22:2: error: ‘asm’ undeclared (first > >use in this function) > >./include/odp_spin_internal.h:22:2: note: each undeclared > >identifier is reported only once for each function it appears in > >./include/odp_spin_internal.h:22:6: error: expected ‘;’ before > >‘__volatile__’ > >./include/odp_spin_internal.h: In function ‘odp_spin’: > >./include/odp_spin_internal.h:34:2: error: ‘asm’ undeclared (first > >use in this function) > >./include/odp_spin_internal.h:34:6: error: expected ‘;’ before > >‘__volatile__’ > >make[1]: *** [obj/odp_barrier.o] Error 1 > >make[1]: Leaving directory > >`/home/huawei/linaro/odp/platform/linux-generic' > >make: *** [lib] Error 2 > > > >Thanks, > >Weilong > > > > > >On 3 May 2014 07:34, Anders Roxell <anders.roxell@linaro.org > ><mailto:anders.roxell@linaro.org>> wrote: > > > > On 2014-04-29 17:03, Weilong Chen wrote: > > > odp_generator can send/receive udp packets, or works like ping. > > > Work mode: > > > 1.send udp packets > > > odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 --dstmac > > 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m u > > > 2.receive udp packets > > > odp_generator -I eth0 -m r > > > 3.work likes ping > > > odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 --dstmac > > 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m p > > > > > > Mandatory OPTIONS: > > > -I, --interface Eth interfaces (comma-separated, no spaces) > > > -a, --srcmac src mac address > > > -b, --dstmac dst mac address > > > -c, --srcip src ip address > > > -d, --dstip dst ip address > > > -s, --packetsize payload length of the packets > > > -m, --mode work mode: send udp(u), receive(r), send icmp(p) > > > -n, --count the number of packets to be send > > > -t, --timeout only for ping mode, wait ICMP reply timeout seconds > > > -i, --interval wait interval ms between sending each packet > > > default is 1000ms. 0 for flood mode > > > > > > Signed-off-by: Weilong Chen <weilong.chen@linaro.org > > <mailto:weilong.chen@linaro.org>> > > > > Couldn't build with -std=C99 > > > > $ make CC=gcc CFLAGS="-std=c99" > > Compiling odp_generator.c > > gcc -c -MD -DODP_DEBUG=1 -O3 -pthread -W -Wall -Werror -Ws > > > > trict-prototypes -Wmissing-prototypes -Wmissing-declarations > > -Wold-style-definition -Wpointer-arith -Wcast-align > > -Wnested-externs -Wcast-qual -Wformat-nonliteral -Wformat-security > > -Wundef -Wwrite-strings -I../../include > > -I../../platform/linux-generic/include/api -std=c99 -o > > obj/odp_generator.o odp_generator.c > > odp_generator.c: In function ‘gen_send_thread’: > > odp_generator.c:341:4: error: implicit declaration of function > > ‘usleep’ [-Werror=implicit-function-declaration] > > usleep(args->appl.interval * 1000); > > ^ > > odp_generator.c:341:4: error: nested extern declaration of > > ‘usleep’ [-Werror=nested-externs] > > odp_generator.c: In function ‘parse_args’: > > odp_generator.c:727:5: error: implicit declaration of function > > ‘strtok_r’ [-Werror=implicit-function-declaration] > > token = strtok_r(str, ",", &save); > > ^ > > odp_generator.c:727:5: error: nested extern declaration of > > ‘strtok_r’ [-Werror=nested-externs] > > odp_generator.c:727:11: error: assignment makes pointer from > > integer without a cast [-Werror] > > token = strtok_r(str, ",", &save); > > ^ > > odp_generator.c:745:11: error: assignment makes pointer from > > integer without a cast [-Werror] > > token = strtok_r(str, ",", &save); > > ^ > > cc1: all warnings being treated as errors > > make: *** [obj/odp_generator.o] Error 1 > > > > > > Cheers, > > Anders > > > > > > > > > >_______________________________________________ > >lng-odp mailing list > >lng-odp@lists.linaro.org > >http://lists.linaro.org/mailman/listinfo/lng-odp > > > _______________________________________________ > lng-odp mailing list > lng-odp@lists.linaro.org > http://lists.linaro.org/mailman/listinfo/lng-odp
diff --git a/.gitignore b/.gitignore index 781932c..b4c7017 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ test/api_test/odp_shm test/api_test/odp_ring test/api_test/odp_timer test/timer/odp_timer_test +test/generator/odp_generator diff --git a/test/Makefile b/test/Makefile index 9e3c482..cc3f4e9 100644 --- a/test/Makefile +++ b/test/Makefile @@ -10,6 +10,7 @@ all: $(MAKE) -C packet $(MAKE) -C packet_netmap $(MAKE) -C timer + $(MAKE) -C generator .PHONY: clean clean: @@ -18,6 +19,7 @@ clean: $(MAKE) -C packet clean $(MAKE) -C packet_netmap clean $(MAKE) -C timer clean + $(MAKE) -C generator clean .PHONY: install install: @@ -26,3 +28,4 @@ install: $(MAKE) -C packet install $(MAKE) -C packet_netmap install $(MAKE) -C timer install + $(MAKE) -C generator install diff --git a/test/generator/Makefile b/test/generator/Makefile new file mode 100644 index 0000000..d1f288d --- /dev/null +++ b/test/generator/Makefile @@ -0,0 +1,46 @@ +# Copyright (c) 2014, Linaro Limited +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause + +ODP_ROOT = ../.. +ODP_APP = odp_generator + +include $(ODP_ROOT)/Makefile.inc +include ../Makefile.inc + +.PHONY: default +default: $(OBJ_DIR) $(ODP_APP) + +OBJS = +OBJS += $(OBJ_DIR)/odp_generator.o + +DEPS = $(OBJS:.o=.d) + +-include $(DEPS) + + +# +# Compile rules +# +$(OBJ_DIR)/%.o: %.c + $(ECHO) Compiling $< + $(CC) -c -MD $(EXTRA_CFLAGS) $(CFLAGS) -o $@ $< + +# +# Link rule +# +$(ODP_APP): $(ODP_LIB) $(OBJS) + $(ECHO) Linking $< + $(CC) $(LDFLAGS) $(OBJS) $(ODP_LIB) $(STD_LIBS) -o $@ + +.PHONY: clean +clean: + $(RMDIR) $(OBJ_DIR) + $(RM) $(ODP_APP) + $(MAKE) -C $(ODP_DIR) clean + +.PHONY: install +install: + install -d $(DESTDIR)/share/odp + install -m 0755 $(ODP_APP) $(DESTDIR)/share/odp/ diff --git a/test/generator/odp_generator.c b/test/generator/odp_generator.c new file mode 100644 index 0000000..10b60ca --- /dev/null +++ b/test/generator/odp_generator.c @@ -0,0 +1,921 @@ +/* Copyright (c) 2014, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * + * @example odp_generator.c ODP loopback demo application + */ + +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <unistd.h> +#include <sys/time.h> + +#include <odp.h> +#include <odp_packet_io.h> +#include <helper/odp_linux.h> +#include <helper/odp_packet_helper.h> +#include <helper/odp_eth.h> +#include <helper/odp_ip.h> +#include <helper/odp_udp.h> +#include <helper/odp_icmp.h> + +#define MAX_WORKERS 32 /**< max number of works */ +#define SHM_PKT_POOL_SIZE (512*2048) /**< pkt pool size */ +#define SHM_PKT_POOL_BUF_SIZE 1856 /**< pkt pool buf size */ + +#define APPL_MODE_UDP 0 /**< UDP mode */ +#define APPL_MODE_PING 1 /**< ping mode */ +#define APPL_MODE_RCV 2 /**< receive mode */ + +/** print appl mode */ +#define PRINT_APPL_MODE(x) printf("%s(%i)\n", #x, (x)) + +/** Get rid of path in filename - only for unix-type paths using '/' */ +#define NO_PATH(file_name) (strrchr((file_name), '/') ? \ + strrchr((file_name), '/') + 1 : (file_name)) +/** + * Parsed command line application arguments + */ +typedef struct { + int core_count; /**< system core count */ + int if_count; /**< Number of interfaces to be used */ + char **if_names; /**< Array of pointers to interface names */ + odp_buffer_pool_t pool; /**< Buffer pool for packet IO */ + odp_ethaddr_t srcmac; /**< src mac addr */ + odp_ethaddr_t dstmac; /**< dest mac addr */ + unsigned int srcip; /**< src ip addr */ + unsigned int dstip; /**< dest ip addr */ + int mode; /**< work mode */ + int number; /**< packets number to be sent */ + int payload; /**< data len */ + int timeout; /**< wait time */ + int interval; /**< wait interval ms between sending each packet */ +} appl_args_t; + +/** + * counters +*/ +struct { + odp_atomic_u64_t seq; /**< ip seq to be send */ + odp_atomic_u64_t ip; /**< ip packets */ + odp_atomic_u64_t udp; /**< udp packets */ + odp_atomic_u64_t icmp; /**< icmp packets */ +} counters; + +/** * Thread specific arguments + */ +typedef struct { + char *pktio_dev; /**< Interface name to use */ + odp_buffer_pool_t pool; /**< Buffer pool for packet IO */ + int mode; /**< Thread mode */ +} thread_args_t; + +/** + * Grouping of both parsed CL args and thread specific args - alloc together + */ +typedef struct { + /** Application (parsed) arguments */ + appl_args_t appl; + /** Thread specific arguments */ + thread_args_t thread[MAX_WORKERS]; +} args_t; + +/** Global pointer to args */ +static args_t *args; + +/* helper funcs */ +static void parse_args(int argc, char *argv[], appl_args_t *appl_args); +static void print_info(char *progname, appl_args_t *appl_args); +static void usage(char *progname); +static int scan_ip(char *buf, unsigned int *paddr); +static int scan_mac(char *in, odp_ethaddr_t *des); +static void tv_sub(struct timeval *recvtime, struct timeval *sendtime); + +/** + * Scan ip + * Parse ip address. + * + * @param buf ip address string xxx.xxx.xxx.xx + * @param paddr ip address for odp_packet + * @return 1 success, 0 failed +*/ +int scan_ip(char *buf, unsigned int *paddr) +{ + int part1, part2, part3, part4; + char tail = 0; + int field; + + if (buf == NULL) + return 0; + + field = sscanf(buf, "%d . %d . %d . %d %c", + &part1, &part2, &part3, &part4, &tail); + + if (field < 4 || field > 5) { + printf("expect 4 field,get %d/n", field); + return 0; + } + + if (tail != 0) { + printf("ip address mixed with non number/n"); + return 0; + } + + if ((part1 >= 0 && part1 <= 255) && (part2 >= 0 && part2 <= 255) && + (part3 >= 0 && part3 <= 255) && (part4 >= 0 && part4 <= 255)) { + if (paddr) + *paddr = part1 << 24 | part2 << 16 | part3 << 8 | part4; + return 1; + } else { + printf("not good ip %d:%d:%d:%d/n", part1, part2, part3, part4); + } + + return 0; +} + +/** + * Scan mac addr form string + * + * @param in mac string + * @param des mac for odp_packet + * @return 1 success, 0 failed + */ +int scan_mac(char *in, odp_ethaddr_t *des) +{ + int field; + int i; + unsigned int mac[7]; + + field = sscanf(in, "%2x:%2x:%2x:%2x:%2x:%2x", + &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); + + for (i = 0; i < 6; i++) + des->addr[i] = mac[i]; + + if (field != 6) + return 0; + return 1; +} + +/** + * set up an udp packet + * + * @param obuf packet buffer +*/ +static void pack_udp_pkt(odp_buffer_t obuf) +{ + char *buf; + int max; + odp_packet_t pkt; + odp_ethhdr_t *eth; + odp_ipv4hdr_t *ip; + odp_udphdr_t *udp; + unsigned short seq; + + buf = odp_buffer_addr(obuf); + if (buf == NULL) + return; + max = odp_buffer_size(obuf); + if (max <= 0) + return; + + pkt = odp_packet_from_buffer(obuf); + /* ether */ + odp_packet_set_l2_offset(pkt, 0); + eth = (odp_ethhdr_t *)buf; + memcpy((char *)eth->src.addr, args->appl.srcmac.addr, ODP_ETHADDR_LEN); + memcpy((char *)eth->dst.addr, args->appl.dstmac.addr, ODP_ETHADDR_LEN); + eth->type = odp_cpu_to_be_16(ODP_ETHTYPE_IPV4); + /* ip */ + odp_packet_set_l3_offset(pkt, ODP_ETHHDR_LEN); + ip = (odp_ipv4hdr_t *)(buf + ODP_ETHHDR_LEN); + ip->dst_addr = odp_cpu_to_be_32(args->appl.dstip); + ip->src_addr = odp_cpu_to_be_32(args->appl.srcip); + ip->ver_ihl = ODP_IPV4 << 4 | ODP_IPV4HDR_IHL_MIN; + ip->tot_len = odp_cpu_to_be_16(args->appl.payload + ODP_UDPHDR_LEN + + ODP_IPV4HDR_LEN); + ip->proto = ODP_IPPROTO_UDP; + seq = odp_atomic_fetch_add_u64(&counters.seq, 1) % 0xFFFF; + ip->id = odp_cpu_to_be_16(seq); + ip->chksum = 0; + odp_ipv4_csum_update(pkt); + /* udp */ + odp_packet_set_l4_offset(pkt, ODP_ETHHDR_LEN + ODP_IPV4HDR_LEN); + udp = (odp_udphdr_t *)(buf + ODP_ETHHDR_LEN + ODP_IPV4HDR_LEN); + udp->src_port = 0; + udp->dst_port = 0; + udp->length = odp_cpu_to_be_16(args->appl.payload + ODP_UDPHDR_LEN); + udp->chksum = 0; + udp->chksum = odp_ipv4_udp_chksum(pkt); + odp_packet_set_len(pkt, args->appl.payload + ODP_UDPHDR_LEN + + ODP_IPV4HDR_LEN + ODP_ETHHDR_LEN); +} + +/** + * Set up an icmp packet + * + * @param obuf packet buffer +*/ +static void pack_icmp_pkt(odp_buffer_t obuf) +{ + char *buf; + int max; + odp_packet_t pkt; + odp_ethhdr_t *eth; + odp_ipv4hdr_t *ip; + odp_icmphdr_t *icmp; + struct timeval *tval; + unsigned short seq; + + buf = odp_buffer_addr(obuf); + if (buf == NULL) + return; + max = odp_buffer_size(obuf); + if (max <= 0) + return; + + args->appl.payload = 56; + pkt = odp_packet_from_buffer(obuf); + /* ether */ + odp_packet_set_l2_offset(pkt, 0); + eth = (odp_ethhdr_t *)buf; + memcpy((char *)eth->src.addr, args->appl.srcmac.addr, ODP_ETHADDR_LEN); + memcpy((char *)eth->dst.addr, args->appl.dstmac.addr, ODP_ETHADDR_LEN); + eth->type = odp_cpu_to_be_16(ODP_ETHTYPE_IPV4); + /* ip */ + odp_packet_set_l3_offset(pkt, ODP_ETHHDR_LEN); + ip = (odp_ipv4hdr_t *)(buf + ODP_ETHHDR_LEN); + ip->dst_addr = odp_cpu_to_be_32(args->appl.dstip); + ip->src_addr = odp_cpu_to_be_32(args->appl.srcip); + ip->ver_ihl = ODP_IPV4 << 4 | ODP_IPV4HDR_IHL_MIN; + ip->tot_len = odp_cpu_to_be_16(args->appl.payload + ODP_ICMPHDR_LEN + + ODP_IPV4HDR_LEN); + ip->proto = ODP_IPPROTO_ICMP; + seq = odp_atomic_fetch_add_u64(&counters.seq, 1) % 0xffff; + ip->id = odp_cpu_to_be_16(seq); + ip->chksum = 0; + odp_ipv4_csum_update(pkt); + /* icmp */ + icmp = (odp_icmphdr_t *)(buf + ODP_ETHHDR_LEN + ODP_IPV4HDR_LEN); + icmp->type = ICMP_ECHO; + icmp->code = 0; + icmp->un.echo.id = 0; + icmp->un.echo.sequence = ip->id; + tval = (struct timeval *)(buf + ODP_ETHHDR_LEN + ODP_IPV4HDR_LEN + + ODP_ICMPHDR_LEN); + /* TODO This should be changed to use an + * ODP timer API once one exists. */ + gettimeofday(tval, NULL); + icmp->chksum = 0; + icmp->chksum = odp_chksum((unsigned short *)icmp, args->appl.payload + + ODP_ICMPHDR_LEN); + + odp_packet_set_len(pkt, args->appl.payload + ODP_ICMPHDR_LEN + + ODP_IPV4HDR_LEN + ODP_ETHHDR_LEN); +} + +/** + * Packet IO loopback worker thread using ODP queues + * + * @param arg thread arguments of type 'thread_args_t *' + */ + +static void *gen_send_thread(void *arg) +{ + int thr; + odp_pktio_t pktio; + thread_args_t *thr_args; + odp_queue_t outq_def; + odp_pktio_params_t params; + socket_params_t *sock_params = ¶ms.sock_params; + + odp_buffer_t buf; + + thr = odp_thread_id(); + thr_args = arg; + + /* Open a packet IO instance for this thread */ + sock_params->type = 1; + pktio = odp_pktio_open(thr_args->pktio_dev, thr_args->pool, ¶ms); + if (pktio == ODP_PKTIO_INVALID) { + ODP_ERR(" [%02i] Error: pktio create failed\n", thr); + return NULL; + } + + outq_def = odp_pktio_outq_getdef(pktio); + if (outq_def == ODP_QUEUE_INVALID) { + ODP_ERR(" [%02i] Error: def output-Q query\n", thr); + return NULL; + } + + printf(" [%02i] created mode: SEND\n", thr); + for (;;) { + int err; + buf = odp_buffer_alloc(thr_args->pool); + if (!odp_buffer_is_valid(buf)) { + ODP_ERR(" [%2i] alloc_single failed\n", thr); + return NULL; + } + + if (args->appl.mode == APPL_MODE_UDP) + pack_udp_pkt(buf); + else if (args->appl.mode == APPL_MODE_PING) + pack_icmp_pkt(buf); + + err = odp_queue_enq(outq_def, buf); + if (err != 0) { + ODP_ERR(" [%02i] send pkt err!\n", thr); + return NULL; + } + + if (args->appl.interval != 0) { + printf(" [%02i] send pkt no:%lu seq %lu\n", + thr, counters.seq, counters.seq%0xffff); + /* TODO use odp timer */ + usleep(args->appl.interval * 1000); + } else { + /* TODO maybe need a rating control */ + /* flood mode use '\r' instead of '\n' */ + printf(" [%02i] send pkt no:%lu seq %lu\r", + thr, counters.seq, counters.seq%0xffff); + } + if (args->appl.number != -1 && counters.seq + >= (unsigned int)args->appl.number) { + break; + } + } + + /* receive number of reply pks until timeout */ + if (args->appl.mode == APPL_MODE_PING && args->appl.number > 0) { + while (args->appl.timeout >= 0) { + if (counters.icmp >= (unsigned int)args->appl.number) + break; + /* TODO use odp timer */ + sleep(1); + args->appl.timeout--; + } + } + + /* print info */ + if (args->appl.mode == APPL_MODE_UDP) { + printf(" [%02i] total send:%lu\n", thr, counters.seq); + } else if (args->appl.mode == APPL_MODE_PING) { + printf(" [%02i] total send:%lu,total receiver %lu\n", + thr, counters.seq, counters.icmp); + } + return arg; +} + +/** + * Print odp packets + * + * @param thr worker id + * @param pkt_tbl packets to be print + * @param len packet number + */ +static void print_pkts(int thr, odp_packet_t pkt_tbl[], unsigned len) +{ + odp_packet_t pkt; + char *buf; + odp_ipv4hdr_t *ip; + odp_udphdr_t *udp; + odp_icmphdr_t *icmp; + struct timeval tvrecv; + struct timeval *tvsend; + double rtt; + unsigned i; + size_t offset; + char msg[1024]; + int rlen; + for (i = 0; i < len; ++i) { + pkt = pkt_tbl[i]; + rlen = 0; + + /* only ip pkts */ + if (!odp_packet_inflag_ipv4(pkt)) + continue; + + odp_atomic_inc_u64(&counters.ip); + rlen += sprintf(msg, "receive Packet proto:IP "); + buf = odp_buffer_addr(odp_buffer_from_packet(pkt)); + ip = (odp_ipv4hdr_t *)(buf + odp_packet_l3_offset(pkt)); + rlen += sprintf(msg + rlen, "id %d ", + odp_be_to_cpu_16(ip->id)); + offset = odp_packet_l4_offset(pkt); + + /* udp */ + if (ip->proto == ODP_IPPROTO_UDP) { + odp_atomic_inc_u64(&counters.udp); + udp = (odp_udphdr_t *)(buf + offset); + rlen += sprintf(msg + rlen, "UDP payload %d ", + odp_be_to_cpu_16(udp->length) - + ODP_UDPHDR_LEN); + } + + /* icmp */ + if (ip->proto == ODP_IPPROTO_ICMP) { + icmp = (odp_icmphdr_t *)(buf + offset); + /* echo reply */ + if (icmp->type == ICMP_ECHOREPLY) { + odp_atomic_inc_u64(&counters.icmp); + tvsend = (struct timeval *)(buf + offset + + ODP_ICMPHDR_LEN); + /* TODO This should be changed to use an + * ODP timer API once one exists. */ + gettimeofday(&tvrecv, NULL); + tv_sub(&tvrecv, tvsend); + rtt = tvrecv.tv_sec*1000 + tvrecv.tv_usec/1000; + rlen += sprintf(msg + rlen, + "ICMP Echo Reply seq %d time %.1f ", + odp_be_to_cpu_16(icmp->un.echo.sequence) + , rtt); + } else if (icmp->type == ICMP_ECHO) { + rlen += sprintf(msg + rlen, + "Icmp Echo Request"); + } + } + + msg[rlen] = '\0'; + printf(" [%02i] %s\n", thr, msg); + } +} + +/** + * Main receive funtion + * + * @param arg thread arguments of type 'thread_args_t *' + */ +static void *gen_recv_thread(void *arg) +{ + int thr; + odp_pktio_t pktio; + thread_args_t *thr_args; + odp_queue_t inq_def; + odp_pktio_params_t params; + char inq_name[ODP_QUEUE_NAME_LEN]; + odp_queue_param_t qparam; + socket_params_t *sock_params = ¶ms.sock_params; + + odp_packet_t pkt; + odp_buffer_t buf; + + thr = odp_thread_id(); + thr_args = arg; + + /* Open a packet IO instance for this thread */ + sock_params->type = 1; + pktio = odp_pktio_open(thr_args->pktio_dev, thr_args->pool, ¶ms); + if (pktio == ODP_PKTIO_INVALID) { + ODP_ERR(" [%02i] Error: pktio create failed\n", thr); + return NULL; + } + + int ret; + qparam.sched.prio = ODP_SCHED_PRIO_DEFAULT; + qparam.sched.sync = ODP_SCHED_SYNC_ATOMIC; + qparam.sched.group = ODP_SCHED_GROUP_DEFAULT; + snprintf(inq_name, sizeof(inq_name), "%i-pktio_inq_def", (int)pktio); + inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0'; + inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN, &qparam); + if (inq_def == ODP_QUEUE_INVALID) { + ODP_ERR(" [%02i] Error: pktio queue creation failed\n", thr); + return NULL; + } + + ret = odp_pktio_inq_setdef(pktio, inq_def); + if (ret != 0) { + ODP_ERR(" [%02i] Error: default input-Q setup\n", thr); + return NULL; + } + + printf(" [%02i] created mode: RECEIVE\n", thr); + for (;;) { + /* Use schedule to get buf from any input queue */ + buf = odp_schedule(NULL, ODP_SCHED_WAIT); + + pkt = odp_packet_from_buffer(buf); + /* Drop packets with errors */ + if (odp_unlikely(odp_packet_error(pkt))) { + odp_packet_free(pkt); + continue; + } + + print_pkts(thr, &pkt, 1); + + odp_packet_free(pkt); + } + + return arg; +} +/** + * ODP packet example main function + */ +int main(int argc, char *argv[]) +{ + odp_linux_pthread_t thread_tbl[MAX_WORKERS]; + odp_buffer_pool_t pool; + int thr_id; + int num_workers; + void *pool_base; + int i; + int first_core; + int core_count; + + /* Init ODP before calling anything else */ + if (odp_init_global()) { + ODP_ERR("Error: ODP global init failed.\n"); + exit(EXIT_FAILURE); + } + + /* init counters */ + odp_atomic_init_u64(&counters.seq); + odp_atomic_init_u64(&counters.ip); + odp_atomic_init_u64(&counters.udp); + odp_atomic_init_u64(&counters.icmp); + + /* Reserve memory for args from shared mem */ + args = odp_shm_reserve("shm_args", sizeof(args_t), ODP_CACHE_LINE_SIZE); + if (args == NULL) { + ODP_ERR("Error: shared mem alloc failed.\n"); + exit(EXIT_FAILURE); + } + memset(args, 0, sizeof(*args)); + + /* Parse and store the application arguments */ + parse_args(argc, argv, &args->appl); + + /* Print both system and application information */ + print_info(NO_PATH(argv[0]), &args->appl); + + core_count = odp_sys_core_count(); + num_workers = core_count; + + if (args->appl.core_count) + num_workers = args->appl.core_count; + + if (num_workers > MAX_WORKERS) + num_workers = MAX_WORKERS; + + /* ping mode need two worker */ + if (args->appl.mode == APPL_MODE_PING) + num_workers = 2; + + printf("Num worker threads: %i\n", num_workers); + + /* + * By default core #0 runs Linux kernel background tasks. + * Start mapping thread from core #1 + */ + first_core = 1; + + if (core_count == 1) + first_core = 0; + + printf("First core: %i\n\n", first_core); + + /* Init this thread */ + thr_id = odp_thread_create(0); + odp_init_local(thr_id); + + /* Create packet pool */ + pool_base = odp_shm_reserve("shm_packet_pool", + SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE); + if (pool_base == NULL) { + ODP_ERR("Error: packet pool mem alloc failed.\n"); + exit(EXIT_FAILURE); + } + + pool = odp_buffer_pool_create("packet_pool", pool_base, + SHM_PKT_POOL_SIZE, + SHM_PKT_POOL_BUF_SIZE, + ODP_CACHE_LINE_SIZE, + ODP_BUFFER_TYPE_PACKET); + if (pool == ODP_BUFFER_POOL_INVALID) { + ODP_ERR("Error: packet pool create failed.\n"); + exit(EXIT_FAILURE); + } + odp_buffer_pool_print(pool); + + /* Create and init worker threads */ + memset(thread_tbl, 0, sizeof(thread_tbl)); + + if (args->appl.mode == APPL_MODE_PING) { + args->thread[1].pktio_dev = args->appl.if_names[0]; + args->thread[1].pool = pool; + args->thread[1].mode = args->appl.mode; + odp_linux_pthread_create(thread_tbl, 1, 0, + gen_recv_thread, &args->thread[1]); + + args->thread[0].pktio_dev = args->appl.if_names[0]; + args->thread[0].pool = pool; + args->thread[0].mode = args->appl.mode; + odp_linux_pthread_create(thread_tbl, 1, 0, + gen_send_thread, &args->thread[0]); + + /* only wait send thread to join */ + num_workers = 1; + } else { + for (i = 0; i < num_workers; ++i) { + void *(*thr_run_func) (void *); + int core; + int if_idx; + + core = (first_core + i) % core_count; + + if_idx = i % args->appl.if_count; + + args->thread[i].pktio_dev = args->appl.if_names[if_idx]; + args->thread[i].pool = pool; + args->thread[i].mode = args->appl.mode; + + if (args->appl.mode == APPL_MODE_UDP) { + thr_run_func = gen_send_thread; + } else if (args->appl.mode == APPL_MODE_RCV) { + thr_run_func = gen_recv_thread; + } else { + ODP_ERR("ERR MODE\n"); + exit(EXIT_FAILURE); + } + /* + * Create threads one-by-one instead of all-at-once, + * because each thread might get different arguments. + * Calls odp_thread_create(cpu) for each thread + */ + odp_linux_pthread_create(thread_tbl, 1, + core, thr_run_func, + &args->thread[i]); + } + } + + /* Master thread waits for other threads to exit */ + odp_linux_pthread_join(thread_tbl, num_workers); + printf("Exit\n\n"); + + return 0; +} + + +/** + * Parse and store the command line arguments + * + * @param argc argument count + * @param argv[] argument vector + * @param appl_args Store application arguments here + */ +static void parse_args(int argc, char *argv[], appl_args_t *appl_args) +{ + int opt; + int long_index; + char *names, *str, *token, *save; + size_t len; + int i; + static struct option longopts[] = { + {"interface", required_argument, NULL, 'I'}, + {"workers", required_argument, NULL, 'w'}, + {"srcmac", required_argument, NULL, 'a'}, + {"dstmac", required_argument, NULL, 'b'}, + {"srcip", required_argument, NULL, 'c'}, + {"dstip", required_argument, NULL, 'd'}, + {"packetsize", required_argument, NULL, 's'}, + {"mode", required_argument, NULL, 'm'}, + {"count", required_argument, NULL, 'n'}, + {"timeout", required_argument, NULL, 't'}, + {"interval", required_argument, NULL, 'i'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + appl_args->mode = -1; /* Invalid, must be changed by parsing */ + appl_args->number = -1; + appl_args->payload = 56; + appl_args->timeout = -1; + + while (1) { + opt = getopt_long(argc, argv, "+I:a:b:c:d:s:i:m:n:t:w:h", + longopts, &long_index); + if (opt == -1) + break; /* No more options */ + + switch (opt) { + case 'w': + appl_args->core_count = atoi(optarg); + break; + /* parse packet-io interface names */ + case 'I': + len = strlen(optarg); + if (len == 0) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + len += 1; /* add room for '\0' */ + + names = malloc(len); + if (names == NULL) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + /* count the number of tokens separated by ',' */ + strcpy(names, optarg); + for (str = names, i = 0;; str = NULL, i++) { + token = strtok_r(str, ",", &save); + if (token == NULL) + break; + } + appl_args->if_count = i; + + if (appl_args->if_count == 0) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + /* allocate storage for the if names */ + appl_args->if_names = + calloc(appl_args->if_count, sizeof(char *)); + + /* store the if names (reset names string) */ + strcpy(names, optarg); + for (str = names, i = 0;; str = NULL, i++) { + token = strtok_r(str, ",", &save); + if (token == NULL) + break; + appl_args->if_names[i] = token; + } + break; + + case 'm': + if (optarg[0] == 'u') { + appl_args->mode = APPL_MODE_UDP; + } else if (optarg[0] == 'p') { + appl_args->mode = APPL_MODE_PING; + } else if (optarg[0] == 'r') { + appl_args->mode = APPL_MODE_RCV; + } else { + ODP_ERR("wrong mode!\n"); + exit(EXIT_FAILURE); + } + break; + + case 'a': + if (scan_mac(optarg, &appl_args->srcmac) != 1) { + ODP_ERR("wrong src mac:%s\n", optarg); + exit(EXIT_FAILURE); + } + break; + + case 'b': + if (scan_mac(optarg, &appl_args->dstmac) != 1) { + ODP_ERR("wrong dst mac:%s\n", optarg); + exit(EXIT_FAILURE); + } + break; + + case 'c': + if (scan_ip(optarg, &appl_args->srcip) != 1) { + ODP_ERR("wrong src ip:%s\n", optarg); + exit(EXIT_FAILURE); + } + break; + + case 'd': + if (scan_ip(optarg, &appl_args->dstip) != 1) { + ODP_ERR("wrong dst ip:%s\n", optarg); + exit(EXIT_FAILURE); + } + break; + + case 's': + appl_args->payload = atoi(optarg); + break; + + case 'n': + appl_args->number = atoi(optarg); + break; + + case 't': + appl_args->timeout = atoi(optarg); + break; + + case 'i': + appl_args->interval = atoi(optarg); + if (appl_args->interval <= 200 && geteuid() != 0) { + ODP_ERR("should be root user\n"); + exit(EXIT_FAILURE); + } + break; + + case 'h': + usage(argv[0]); + exit(EXIT_SUCCESS); + break; + + default: + break; + } + } + + if (appl_args->if_count == 0 || appl_args->mode == -1) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + optind = 1; /* reset 'extern optind' from the getopt lib */ +} + +/** + * Print system and application info + */ +static void print_info(char *progname, appl_args_t *appl_args) +{ + int i; + + printf("\n" + "ODP system info\n" + "---------------\n" + "ODP API version: %s\n" + "CPU model: %s\n" + "CPU freq (hz): %"PRIu64"\n" + "Cache line size: %i\n" + "Core count: %i\n" + "\n", + odp_version_api_str(), odp_sys_cpu_model_str(), odp_sys_cpu_hz(), + odp_sys_cache_line_size(), odp_sys_core_count()); + + printf("Running ODP appl: \"%s\"\n" + "-----------------\n" + "IF-count: %i\n" + "Using IFs: ", + progname, appl_args->if_count); + for (i = 0; i < appl_args->if_count; ++i) + printf(" %s", appl_args->if_names[i]); + printf("\n" + "Mode: "); + if (appl_args->mode == 0) + PRINT_APPL_MODE(0); + else + PRINT_APPL_MODE(0); + printf("\n\n"); + fflush(NULL); +} + +/** + * Prinf usage information + */ +static void usage(char *progname) +{ + printf("\n" + "Usage: %s OPTIONS\n" + " E.g. %s -I eth1 -r\n" + "\n" + "OpenDataPlane example application.\n" + "\n" + " Work mode:\n" + " 1.send udp packets\n" + " odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 --dstmac 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m u\n" + " 2.receive udp packets\n" + " odp_generator -I eth0 -m r\n" + " 3.work likes ping\n" + " odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 --dstmac 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m p\n" + "\n" + "Mandatory OPTIONS:\n" + " -I, --interface Eth interfaces (comma-separated, no spaces)\n" + " -a, --srcmac src mac address\n" + " -b, --dstmac dst mac address\n" + " -c, --srcip src ip address\n" + " -d, --dstip dst ip address\n" + " -s, --packetsize payload length of the packets\n" + " -m, --mode work mode: send udp(u), receive(r), send icmp(p)\n" + " -n, --count the number of packets to be send\n" + " -t, --timeout only for ping mode, wait ICMP reply timeout seconds\n" + " -i, --interval wait interval ms between sending each packet\n" + " default is 1000ms. 0 for flood mode\n" + "\n" + "Optional OPTIONS\n" + " -h, --help Display help and exit.\n" + "\n", NO_PATH(progname), NO_PATH(progname) + ); +} +/** + * calc time period + * + *@param recvtime start time + *@param sendtime end time +*/ +void tv_sub(struct timeval *recvtime, struct timeval *sendtime) +{ + long sec = recvtime->tv_sec - sendtime->tv_sec; + long usec = recvtime->tv_usec - sendtime->tv_usec; + if (usec >= 0) { + recvtime->tv_sec = sec; + recvtime->tv_usec = usec; + } else { + recvtime->tv_sec = sec - 1; + recvtime->tv_usec = -usec; + } +}
odp_generator can send/receive udp packets, or works like ping. Work mode: 1.send udp packets odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 --dstmac 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m u 2.receive udp packets odp_generator -I eth0 -m r 3.work likes ping odp_generator -I eth0 --srcmac fe:0f:97:c9:e0:44 --dstmac 32:cb:9b:27:2f:1a --srcip 192.168.0.1 --dstip 192.168.0.2 -m p Mandatory OPTIONS: -I, --interface Eth interfaces (comma-separated, no spaces) -a, --srcmac src mac address -b, --dstmac dst mac address -c, --srcip src ip address -d, --dstip dst ip address -s, --packetsize payload length of the packets -m, --mode work mode: send udp(u), receive(r), send icmp(p) -n, --count the number of packets to be send -t, --timeout only for ping mode, wait ICMP reply timeout seconds -i, --interval wait interval ms between sending each packet default is 1000ms. 0 for flood mode Signed-off-by: Weilong Chen <weilong.chen@linaro.org> --- .gitignore | 1 + test/Makefile | 3 + test/generator/Makefile | 46 ++ test/generator/odp_generator.c | 921 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 971 insertions(+) create mode 100644 test/generator/Makefile create mode 100644 test/generator/odp_generator.c