Message ID | 1395389350-12912-1-git-send-email-weilong.chen@linaro.org |
---|---|
State | Superseded |
Headers | show |
Hi Weilong, Sorry, forget to tell you that you should check your coding style by ./scripts/checkpatch.pl before sending patches. On Fri, Mar 21, 2014 at 4:09 PM, Weilong Chen <weilong.chen@linaro.org>wrote: > odp_generator can send/receive udp packets, or works like ping. > Work mode: > 1.send udp packets > odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a -c > 192.168.0.1 -d 192.168.0.2 -m u > 2.receive udp packets > odp_generator -I eth1 -r > 3.work likes ping > odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a -c > 192.168.0.1 -d 192.168.0.2 -m p > > Signed-off-by: Weilong Chen <weilong.chen@linaro.org> > --- > .gitignore | 1 + > test/Makefile | 3 + > test/generator/Makefile | 46 +++ > test/generator/odp_generator.c | 847 > ++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 897 insertions(+) > create mode 100644 test/generator/Makefile > create mode 100644 test/generator/odp_generator.c > > diff --git a/.gitignore b/.gitignore > index 53454a5..91055bd 100644 > --- a/.gitignore > +++ b/.gitignore > @@ -14,3 +14,4 @@ test/packet_netmap/odp_packet > test/api_test/odp_atomic > test/api_test/odp_shm > test/api_test/odp_ring > +test/generator/odp_generator > diff --git a/test/Makefile b/test/Makefile > index 2ff7a4c..771b3f4 100644 > --- a/test/Makefile > +++ b/test/Makefile > @@ -9,6 +9,7 @@ all: > $(MAKE) -C example > $(MAKE) -C packet > $(MAKE) -C packet_netmap > + $(MAKE) -C generator > > .PHONY: clean > clean: > @@ -16,6 +17,7 @@ clean: > $(MAKE) -C example clean > $(MAKE) -C packet clean > $(MAKE) -C packet_netmap clean > + $(MAKE) -C generator clean > > .PHONY: install > install: > @@ -23,3 +25,4 @@ install: > $(MAKE) -C example install > $(MAKE) -C packet install > $(MAKE) -C packet_netmap install > + $(MAKE) -C generator install > diff --git a/test/generator/Makefile b/test/generator/Makefile > new file mode 100644 > index 0000000..350d2e4 > --- /dev/null > +++ b/test/generator/Makefile > @@ -0,0 +1,46 @@ > +# Copyright (c) 2013, 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..0ec855b > --- /dev/null > +++ b/test/generator/odp_generator.c > @@ -0,0 +1,847 @@ > +/* Copyright (c) 2013, 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 <stdio.h> > +#include<sys/time.h> > + > +#include <odp.h> > +#include <helper/odp_packet_helper.h> > +#include <helper/odp_linux.h> > +#include <helper/odp_eth.h> > +#include <helper/odp_ip.h> > +#include <helper/odp_udp.h> > +#include <odp_packet_io.h> > + > + > +#define SHM_PKT_POOL_SIZE (512*2048) > +#define SHM_PKT_POOL_BUF_SIZE 1856 > + > + > +#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 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 */ > +} appl_args_t; > + > +/** > + * Thread specific arguments > + */ > +typedef struct { > + char *pktio_dev; /**< Interface name to use */ > + odp_buffer_pool_t pool; /**< Buffer pool for packet IO */ > + int mode; /**< 0 send, 1 receive */ > +} thread_args_t; > + > +/** > + * Grouping of both parsed CL args and thread specific args - alloc > together > + */ > +#define MAX_WORKERS 1 > +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 */ > +void tv_sub(struct timeval *recvtime,struct timeval *sendtime); > +static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len); > +static void print_pkts(odp_packet_t pkt_tbl[], unsigned len); > +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); > +unsigned int scan_ip(char *ip); > +int scan_mac(char *in,char *des); > +void compute_ip_checksum(odp_ipv4hdr_t *iphdrp); > +void compute_udp_checksum(odp_ipv4hdr_t *pIph, unsigned short *ipPayload); > + > +/* args */ > +char srcip[20]; > +char dstip[20]; > +char srcmac[20]; > +char dstmac[20]; > +int pksize = 0; > +int interval = 1 * 1000; > +int number = -1; //packets to send > +int timeout = -1; //timeout seconds > +int mode; //0 udp, 1 icmp, 2 r; > +int ipcount; > +int udpcount; > +int icmpcount; > +unsigned long long total; > + > +struct icmphdr { > + u_int8_t type; /* message type */ > + u_int8_t code; /* type sub-code */ > + u_int16_t checksum; > + u_int16_t id; > + u_int16_t sequence; > +}; > + > +/* parser ip */ > +unsigned int scan_ip(char *ip) > +{ > + int part1,part2,part3,part4; > + unsigned int ipi; > + > + sscanf(ip,"%d.%d.%d.%d",&part1,&part2,&part3,&part4); > + ipi = 0; > + ipi = part1 <<24 | part2 << 16| part3 << 8 | part4 ; > + return ipi; > +} > + > +/* parser mac */ > +int scan_mac(char *in,char *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[i] = mac[i]; > + } > + > + return field; > +} > + > +static unsigned short pcount; > + > +/* Compute checksum for count bytes starting at addr, using one's > complement of one's complement sum*/ > +static unsigned short compute_checksum(unsigned short *addr, unsigned int > count) > +{ > + register unsigned long sum = 0; > + while (count > 1) { > + sum += * addr++; > + count -= 2; > + } > + //if any bytes left, pad the bytes and add > + if(count > 0) { > + sum += ((*addr)&odp_cpu_to_be_16(0xFF00)); > + } > + //Fold sum to 16 bits: add carrier to result > + while (sum>>16) { > + sum = (sum & 0xffff) + (sum >> 16); > + } > + //one's complement > + sum = ~sum; > + return ((unsigned short)sum); > +} > + > +/* set ip checksum of a given ip header*/ > +void compute_ip_checksum(odp_ipv4hdr_t *iphdrp) > +{ > + iphdrp->chksum = 0; > + iphdrp->chksum = compute_checksum((unsigned short*)iphdrp, > iphdrp->ver_ihl<<2); > +} > +void compute_udp_checksum(odp_ipv4hdr_t *pIph, unsigned short *ipPayload) > +{ > + register unsigned long sum = 0; > + odp_udphdr_t *udphdrp = (odp_udphdr_t *)(ipPayload); > + unsigned short udpLen = odp_cpu_to_be_16(udphdrp->length); > + //the source ip > + sum += (pIph->src_addr>>16)&0xFFFF; > + sum += (pIph->src_addr)&0xFFFF; > + //the dest ip > + sum += (pIph->dst_addr>>16)&0xFFFF; > + sum += (pIph->dst_addr)&0xFFFF; > + sum += odp_cpu_to_be_16(ODP_IPPROTO_UDP); > + //the length > + sum += udphdrp->length; > + > + //initialize checksum to 0 > + udphdrp->chksum = 0; > + while (udpLen > 1) { > + sum += * ipPayload++; > + udpLen -= 2; > + } > + //if any bytes left, pad the bytes and add > + if(udpLen > 0) { > + sum += ((*ipPayload)&odp_cpu_to_be_16(0xFF00)); > + } > + //Fold sum to 16 bits: add carrier to result > + //printf("add carrier\n"); > + while (sum>>16) { > + sum = (sum & 0xffff) + (sum >> 16); > + } > + //printf("one's complement\n"); > + sum = ~sum; > + //set computation result > + udphdrp->chksum = ((unsigned short)sum == 0x0000)?0xFFFF:(unsigned > short)sum; > +} > + > +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; > + > + buf = odp_buffer_addr(obuf); > + if(buf == NULL) > + return; > + max = odp_buffer_size(obuf); > + if(max <= 0) > + return; > + > + memset(buf, 0, max); > + pkt = odp_packet_from_buffer(obuf); > + //ether > + odp_packet_set_l2_offset(pkt, 0); > + eth = (odp_ethhdr_t *)buf; > + scan_mac(dstmac,(char *)eth->dst.addr); > + scan_mac(srcmac,(char *)eth->src.addr); > + eth->type = odp_cpu_to_be_16 (ODP_ETHTYPE_IPV4); > + //ip > + odp_packet_set_l3_offset(pkt, 14); > + ip = (odp_ipv4hdr_t *)(buf + 14); > + ip->dst_addr = odp_cpu_to_be_32(scan_ip(dstip)); > + ip->src_addr = odp_cpu_to_be_32(scan_ip(srcip)); > + ip->ver_ihl = ODP_IPV4<<4|5; > + ip->tot_len = odp_cpu_to_be_16(pksize + 8 + 20); > + ip->proto = ODP_IPPROTO_UDP; > + ip->id = odp_cpu_to_be_16(pcount++); > + compute_ip_checksum(ip); > + //udp > + udp = (odp_udphdr_t *) (buf + 14 + 20); > + udp->src_port = 0; > + udp->dst_port = 0; > + udp->length = odp_cpu_to_be_16(pksize + 8); > + udp->chksum = 0; > + compute_udp_checksum(ip, (unsigned short *)udp); > + > + odp_packet_set_len(pkt,pksize + 8 + 20 + 14); > +} > + > +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; > + struct icmphdr *icmp; > + struct timeval *tval; > + > + buf = odp_buffer_addr(obuf); > + if(buf == NULL) > + return; > + max = odp_buffer_size(obuf); > + if(max <= 0) > + return; > + > + memset(buf, 0, max); > + pksize = 56; //set icmp size 56 > + pkt = odp_packet_from_buffer(obuf); > + //ether > + odp_packet_set_l2_offset(pkt, 0); > + eth = (odp_ethhdr_t *)buf; > + scan_mac(dstmac,(char *)eth->dst.addr); > + scan_mac(srcmac,(char *)eth->src.addr); > + eth->type = odp_cpu_to_be_16 (ODP_ETHTYPE_IPV4); > + //ip > + odp_packet_set_l3_offset(pkt, 14); > + ip = (odp_ipv4hdr_t *)(buf + 14); > + ip->dst_addr = odp_cpu_to_be_32(scan_ip(dstip)); > + ip->src_addr = odp_cpu_to_be_32(scan_ip(srcip)); > + ip->ver_ihl = ODP_IPV4<<4|5; > + ip->tot_len = odp_cpu_to_be_16(56 + 8 + 20); > + ip->proto = ODP_IPPROTO_ICMP; > + ip->id = odp_cpu_to_be_16(pcount++); > + compute_ip_checksum(ip); > + //icmp > + icmp = (struct icmphdr *) (buf + 14 + 20); > + icmp->type = 8; //Echo Request > + icmp->code = 0; > + icmp->id = odp_cpu_to_be_16(pcount - 1); > + icmp->sequence = odp_cpu_to_be_16(pcount - 1); > + tval = (struct timeval *)(buf + 14 + 20 + 8); > + gettimeofday(tval,NULL); > + icmp->checksum = 0; > + icmp->checksum = compute_checksum((unsigned short *)icmp, 64); > + > + odp_packet_set_len(pkt,56 + 8 + 20 + 14); > +} > + > + > + > +/** > + * Packet IO loopback worker thread using ODP queues > + * > + * @param arg thread arguments of type 'thread_args_t *' > + */ > +static void *pktio_queue_thread(void *arg) > +{ > + int thr; > + odp_buffer_pool_t pkt_pool; > + odp_pktio_t pktio; > + thread_args_t *thr_args; > + odp_queue_t outq_def; > + 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; > + > + if(mode == 1&& thr_args->mode != 2) > + sleep(1); //wait receiver ok; > + printf("Pktio thread [%02i] starts, pktio_dev:%s\n", thr, > + thr_args->pktio_dev); > + > + /* Lookup the packet pool */ > + pkt_pool = odp_buffer_pool_lookup("packet_pool"); > + if (pkt_pool == ODP_BUFFER_POOL_INVALID) { > + ODP_ERR(" [%02i] Error: pkt_pool not found\n", thr); > + return NULL; > + } > + > + /* Open a packet IO instance for this thread */ > + sock_params->type = ODP_PKTIO_TYPE_SOCKET; > + 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; > + } > + > + if (thr_args->mode == 0 || thr_args->mode == 1) { > + 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; > + } > + > + for(;;) { > + int err; > + buf = odp_buffer_alloc(pkt_pool); > + if (!odp_buffer_is_valid(buf)) { > + ODP_ERR(" [%i] alloc_single failed\n", > thr); > + return NULL; > + } > + > + if(thr_args->mode == 0) > + pack_udp_pkt(buf); > + else > + pack_icmp_pkt(buf); > + > + err = odp_queue_enq(outq_def, buf); > + total++; > + if (err != 0) { > + printf("send pkt err!\n"); > + return NULL; > + } > + if(interval != 0) { //flood mode will not print msg > + printf("Generator send pkt no:%llu seq %d > size:%d\n", total,pcount - 1, pksize); > + usleep(interval * 1000); > + } else { > + printf("Generator send pkt no:%llu seq %d > size:%d\r", total,pcount - 1, pksize); > + } > + if (number != -1 && (int)total >= number) { > + break; > + } > + > + } > + //if timeout >= 0; > + while(mode == 1 && timeout >= 0) { > + if(icmpcount >= number) > + break; > + sleep(1); > + timeout--; > + } > + //print info: > + if(mode == 0) { > + printf("Total send:%llu\n",total); > + } else if (mode == 1) { > + printf("Total send:%llu,total receiver > %d\n",total,icmpcount); > + } > + exit(0); > + > + } else if(thr_args->mode == 2) { > + 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; > + } > + > + for (;;) { > + /* Use schedule to get buf from any input queue */ > + buf = odp_schedule(NULL); > + > + pkt = odp_packet_from_buffer(buf); > + /* Drop packets with errors */ > + if (odp_unlikely(drop_err_pkts(&pkt, 1) == 0)) { > + ODP_ERR("Drop frame\n"); > + continue; > + } > + > + /* Swap Eth MACs and possibly IP-addrs before > sending back */ > + print_pkts(&pkt, 1); > + > + odp_packet_free(pkt); > + > + } > + > + } > + > + return arg; > +} > + > +/** > + * Swap eth src<->dst and IP src<->dst addresses > + * > + * @param pkt_tbl Array of packets > + * @param len Length of pkt_tbl[] > + */ > + > +static void print_pkts(odp_packet_t pkt_tbl[], unsigned len) > +{ > + odp_packet_t pkt; > + char *buf; > + odp_ipv4hdr_t *ip; > + odp_udphdr_t *udp; > + struct icmphdr *icmp; > + struct timeval tvrecv; > + struct timeval *tvsend; > + double rtt; > + unsigned i; > + char msg[1024]; > + int rlen = 0; > + FILE *stream; > + for (i = 0; i < len; ++i) { > + pkt = pkt_tbl[i]; > + memset(msg, 0, 1024); > + // print ip header > + if(odp_packet_inflag_ipv4(pkt)) { > + ipcount++; > + 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)); > + //ip = (odp_ipv4hdr_t *)odp_packet_l3(pkt); > + rlen += sprintf(msg + rlen,"id %d > ",odp_be_to_cpu_16(ip->id)); > + > + //udp > + if(ip->proto == ODP_IPPROTO_UDP) { > + udpcount++; > + udp = (odp_udphdr_t *)(buf + > odp_packet_l4_offset(pkt)); > + rlen += sprintf(msg + rlen," UDP payload > %d ",odp_be_to_cpu_16(udp->length) - 8); > + } > + > + //icmp > + if(ip->proto == ODP_IPPROTO_ICMP) { > + icmp = (struct icmphdr *)(buf + > odp_packet_l4_offset(pkt)); > + if(icmp->type == 0) { > + icmpcount++; > + tvsend = (struct timeval *)(buf + > odp_packet_l4_offset(pkt) + 8); > + gettimeofday(&tvrecv,NULL); > + tv_sub(&tvrecv,tvsend); > + rtt = tvrecv.tv_sec*1000 + > tvrecv.tv_usec/1000; > + rlen += sprintf(msg + rlen, "ICMP > seq %d time %.1f ",odp_be_to_cpu_16(icmp->sequence), rtt); > + if(mode == 1) //ping mode > + printf("%s\n",msg); > + } > + > + } > + if (mode == 2) //receiver mode > + printf("%s\n",msg); > + stream = fopen( "/tmp/recv.log", "a" ); > + fprintf(stream, "Receive pkt > NO:%d\n",odp_be_to_cpu_16(ip->id)); > + fclose( stream ); > + } > + > + } > +} > + > +/** > + * 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; > + > + /* Init ODP before calling anything else */ > + if (odp_init_global()) { > + ODP_ERR("Error: ODP global init failed.\n"); > + exit(EXIT_FAILURE); > + } > + > + /* 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); > + > + /* 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 (mode == 1) > + num_workers = 2; > + else > + num_workers = 1; > + > + if (mode == 0) { > + printf("Work mode: send udp packets\n\n"); > + } else if (mode == 1) { > + printf("Work mode: ping\n\n"); > + } else if (mode == 2) { > + printf("Work mode: receive ip packets\n\n"); > + } else { > + printf("Wrong mode\n"); > + exit(EXIT_FAILURE); > + } > + for (i = 0; i < num_workers; ++i) { > + void *(*thr_run_func) (void *); > + int 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 = mode; > + if(i == 1) > + args->thread[i].mode = 2; > + thr_run_func = pktio_queue_thread; > + /* > + * 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, i, 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 > + */ > +#pragma GCC diagnostic push // require GCC 4.6 > +#pragma GCC diagnostic ignored "-Wcast-qual" > +#pragma GCC diagnostic ignored "-Werror" > +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'}, /* return > 'i' */ > + {"srcmac", required_argument, NULL, 'a'}, /* > return 'm' */ > + {"dstmac", required_argument, NULL, 'b'}, /* > return 'm' */ > + {"srcip", required_argument, NULL, 'c'}, /* > return 'm' */ > + {"dstip", required_argument, NULL, 'd'}, /* > return 'm' */ > + {"packetsize", required_argument, NULL, 's'}, /* > return 'h' */ > + {"mode", required_argument, NULL, 'm'}, > + {"count", required_argument, NULL, 'n'}, > + {"timeout", required_argument, NULL, 't'}, > + {"interval", required_argument, NULL, 'i'}, /* > return 'h' */ > + {"help", no_argument, NULL, 'h'}, /* return > 'h' */ > + {NULL, 0, NULL, 0} > + }; > + > + > + while (1) { > + opt = getopt_long(argc, argv, "+I:a:b:c:d:s:i:m:n:t:h", > longopts, &long_index); > + > + if (opt == -1) > + break; /* No more options */ > + > + switch (opt) { > + /* 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 'a': > + strcpy(srcmac, optarg); > + break; > + case 'b': > + strcpy(dstmac, optarg); > + break; > + > + case 'c': > + strcpy(srcip, optarg); > + break; > + > + case 'd': > + strcpy(dstip, optarg); > + break; > + case 's': > + pksize = atoi(optarg); > + if(pksize > SHM_PKT_POOL_BUF_SIZE - 14 - 20 - 8) { > + printf("the pksize is too big!\n"); > + exit(EXIT_FAILURE); > + } > + break; > + case 'm': > + if(optarg[0] == 'u') { > + mode = 0; > + } else if (optarg[0] == 'p') { > + mode = 1; > + } else if (optarg[0] == 'r') { > + mode = 2; > + } else { > + printf("wrong mode!\n"); > + exit(EXIT_FAILURE); > + } > + break; > + case 'n': > + number = atoi(optarg); > + break; > + case 't': > + timeout = atoi(optarg); > + break; > + case 'i': > + interval = atoi(optarg); > + if(interval <= 200 && geteuid() != 0) { > + printf("Only super-user may set interval > to values less 0.2 seconds.\n"); > + exit(EXIT_FAILURE); > + } > + break; > + case 'h': > + usage(argv[0]); > + exit(EXIT_SUCCESS); > + break; > + > + default: > + break; > + } > + } > + > + > + optind = 1; /* reset 'extern optind' from the getopt > lib */ > +} > +#pragma GCC diagnostic pop > +/** > + * 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 freq (hz): %"PRIu64"\n" > + "Cache line size: %i\n" > + "Core count: %i\n" > + "\n", > + odp_version_api_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\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 veth0 -a fe:0f:97:c9:e0:44 -b > 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m u\n" > + " 2.receive udp packets\n" > + " 3.work likes ping\n" > + " odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b > 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m p\n" > + "\n" > + "Mandatory OPTIONS:\n" > + " -I, --interface Eth interfaces (comma-separated, no > spaces)\n" > + " -a, --srcmac src mac adddress\n" > + " -b, --dstmac dst mac adddress\n" > + " -c, --srcip src ip adddress\n" > + " -d, --dstip dst ip adddress\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 floord mode\n" > + "\n" > + "Optional OPTIONS\n" > + " -h, --help Display help and exit.\n" > + "\n", NO_PATH(progname), NO_PATH(progname) > + ); > +} > +/** > + * Drop packets which input parsing marked as containing errors. > + * > + * Frees packets with error and modifies pkt_tbl[] to only contain > packets with > + * no detected errors. > + * > + * @param pkt_tbl Array of packet > + * @param len Length of pkt_tbl[] > + * > + * @return Number of packets with no detected error > + */ > +static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len) > +{ > + odp_packet_t pkt; > + unsigned pkt_cnt = len; > + unsigned i, j; > + > + for (i = 0, j = 0; i < len; ++i) { > + pkt = pkt_tbl[i]; > + > + if (odp_unlikely(odp_packet_error(pkt))) { > + odp_packet_free(pkt); /* Drop */ > + pkt_cnt--; > + } else if (odp_unlikely(i != j++)) { > + pkt_tbl[j] = pkt; > + } > + } > + > + return pkt_cnt; > +} > + > +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; > + } > +} > -- > 1.7.9.5 > > -- > You received this message because you are subscribed to the Google Groups > "LNG ODP Sub-team - lng-odp@linaro.org" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to lng-odp+unsubscribe@linaro.org. > To post to this group, send email to lng-odp@linaro.org. > Visit this group at http://groups.google.com/a/linaro.org/group/lng-odp/. > To view this discussion on the web visit > https://groups.google.com/a/linaro.org/d/msgid/lng-odp/1395389350-12912-1-git-send-email-weilong.chen%40linaro.org > . > For more options, visit https://groups.google.com/a/linaro.org/d/optout. >
Hi Weilong, please reuse checksum functions from helper, instead of implementing them. Best regards, Maxim.
On 21 March 2014 01:09, Weilong Chen <weilong.chen@linaro.org> wrote: > odp_generator can send/receive udp packets, or works like ping. > Work mode: > 1.send udp packets > odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m u > 2.receive udp packets > odp_generator -I eth1 -r > 3.work likes ping > odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m p > Weilong, Does it work on 2 node connected back2back? does setup need cross wire? Or it will ping / do generator job for any machine..also why are you refering to veth0.. > Signed-off-by: Weilong Chen <weilong.chen@linaro.org> > --- > .gitignore | 1 + > test/Makefile | 3 + > test/generator/Makefile | 46 +++ > test/generator/odp_generator.c | 847 ++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 897 insertions(+) > create mode 100644 test/generator/Makefile > create mode 100644 test/generator/odp_generator.c > > diff --git a/.gitignore b/.gitignore > index 53454a5..91055bd 100644 > --- a/.gitignore > +++ b/.gitignore > @@ -14,3 +14,4 @@ test/packet_netmap/odp_packet > test/api_test/odp_atomic > test/api_test/odp_shm > test/api_test/odp_ring > +test/generator/odp_generator > diff --git a/test/Makefile b/test/Makefile > index 2ff7a4c..771b3f4 100644 > --- a/test/Makefile > +++ b/test/Makefile > @@ -9,6 +9,7 @@ all: > $(MAKE) -C example > $(MAKE) -C packet > $(MAKE) -C packet_netmap > + $(MAKE) -C generator > > .PHONY: clean > clean: > @@ -16,6 +17,7 @@ clean: > $(MAKE) -C example clean > $(MAKE) -C packet clean > $(MAKE) -C packet_netmap clean > + $(MAKE) -C generator clean > > .PHONY: install > install: > @@ -23,3 +25,4 @@ install: > $(MAKE) -C example install > $(MAKE) -C packet install > $(MAKE) -C packet_netmap install > + $(MAKE) -C generator install > diff --git a/test/generator/Makefile b/test/generator/Makefile > new file mode 100644 > index 0000000..350d2e4 > --- /dev/null > +++ b/test/generator/Makefile > @@ -0,0 +1,46 @@ > +# Copyright (c) 2013, 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..0ec855b > --- /dev/null > +++ b/test/generator/odp_generator.c > @@ -0,0 +1,847 @@ > +/* Copyright (c) 2013, 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 <stdio.h> > +#include<sys/time.h> > + > +#include <odp.h> > +#include <helper/odp_packet_helper.h> > +#include <helper/odp_linux.h> > +#include <helper/odp_eth.h> > +#include <helper/odp_ip.h> > +#include <helper/odp_udp.h> > +#include <odp_packet_io.h> > + > + > +#define SHM_PKT_POOL_SIZE (512*2048) > +#define SHM_PKT_POOL_BUF_SIZE 1856 > + > + > +#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 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 */ > +} appl_args_t; > + > +/** > + * Thread specific arguments > + */ > +typedef struct { > + char *pktio_dev; /**< Interface name to use */ > + odp_buffer_pool_t pool; /**< Buffer pool for packet IO */ > + int mode; /**< 0 send, 1 receive */ > +} thread_args_t; > + > +/** > + * Grouping of both parsed CL args and thread specific args - alloc together > + */ > +#define MAX_WORKERS 1 > +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 */ > +void tv_sub(struct timeval *recvtime,struct timeval *sendtime); > +static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len); > +static void print_pkts(odp_packet_t pkt_tbl[], unsigned len); > +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); > +unsigned int scan_ip(char *ip); > +int scan_mac(char *in,char *des); > +void compute_ip_checksum(odp_ipv4hdr_t *iphdrp); > +void compute_udp_checksum(odp_ipv4hdr_t *pIph, unsigned short *ipPayload); > + > +/* args */ > +char srcip[20]; > +char dstip[20]; > +char srcmac[20]; > +char dstmac[20]; > +int pksize = 0; > +int interval = 1 * 1000; > +int number = -1; //packets to send > +int timeout = -1; //timeout seconds > +int mode; //0 udp, 1 icmp, 2 r; > +int ipcount; > +int udpcount; > +int icmpcount; > +unsigned long long total; > + > +struct icmphdr { > + u_int8_t type; /* message type */ > + u_int8_t code; /* type sub-code */ > + u_int16_t checksum; > + u_int16_t id; > + u_int16_t sequence; > +}; > + > +/* parser ip */ > +unsigned int scan_ip(char *ip) > +{ > + int part1,part2,part3,part4; > + unsigned int ipi; > + > + sscanf(ip,"%d.%d.%d.%d",&part1,&part2,&part3,&part4); > + ipi = 0; > + ipi = part1 <<24 | part2 << 16| part3 << 8 | part4 ; > + return ipi; > +} > + > +/* parser mac */ > +int scan_mac(char *in,char *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[i] = mac[i]; > + } > + > + return field; > +} > + > +static unsigned short pcount; > + > +/* Compute checksum for count bytes starting at addr, using one's complement of one's complement sum*/ > +static unsigned short compute_checksum(unsigned short *addr, unsigned int count) > +{ > + register unsigned long sum = 0; > + while (count > 1) { > + sum += * addr++; > + count -= 2; > + } > + //if any bytes left, pad the bytes and add > + if(count > 0) { > + sum += ((*addr)&odp_cpu_to_be_16(0xFF00)); > + } > + //Fold sum to 16 bits: add carrier to result > + while (sum>>16) { > + sum = (sum & 0xffff) + (sum >> 16); > + } > + //one's complement > + sum = ~sum; > + return ((unsigned short)sum); > +} > + > +/* set ip checksum of a given ip header*/ > +void compute_ip_checksum(odp_ipv4hdr_t *iphdrp) > +{ > + iphdrp->chksum = 0; > + iphdrp->chksum = compute_checksum((unsigned short*)iphdrp, iphdrp->ver_ihl<<2); > +} > +void compute_udp_checksum(odp_ipv4hdr_t *pIph, unsigned short *ipPayload) > +{ > + register unsigned long sum = 0; > + odp_udphdr_t *udphdrp = (odp_udphdr_t *)(ipPayload); > + unsigned short udpLen = odp_cpu_to_be_16(udphdrp->length); > + //the source ip > + sum += (pIph->src_addr>>16)&0xFFFF; > + sum += (pIph->src_addr)&0xFFFF; > + //the dest ip > + sum += (pIph->dst_addr>>16)&0xFFFF; > + sum += (pIph->dst_addr)&0xFFFF; > + sum += odp_cpu_to_be_16(ODP_IPPROTO_UDP); > + //the length > + sum += udphdrp->length; > + > + //initialize checksum to 0 > + udphdrp->chksum = 0; > + while (udpLen > 1) { > + sum += * ipPayload++; > + udpLen -= 2; > + } > + //if any bytes left, pad the bytes and add > + if(udpLen > 0) { > + sum += ((*ipPayload)&odp_cpu_to_be_16(0xFF00)); > + } > + //Fold sum to 16 bits: add carrier to result > + //printf("add carrier\n"); > + while (sum>>16) { > + sum = (sum & 0xffff) + (sum >> 16); > + } > + //printf("one's complement\n"); > + sum = ~sum; > + //set computation result > + udphdrp->chksum = ((unsigned short)sum == 0x0000)?0xFFFF:(unsigned short)sum; > +} > + > +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; > + > + buf = odp_buffer_addr(obuf); > + if(buf == NULL) > + return; > + max = odp_buffer_size(obuf); > + if(max <= 0) > + return; > + > + memset(buf, 0, max); > + pkt = odp_packet_from_buffer(obuf); > + //ether > + odp_packet_set_l2_offset(pkt, 0); > + eth = (odp_ethhdr_t *)buf; > + scan_mac(dstmac,(char *)eth->dst.addr); > + scan_mac(srcmac,(char *)eth->src.addr); > + eth->type = odp_cpu_to_be_16 (ODP_ETHTYPE_IPV4); > + //ip > + odp_packet_set_l3_offset(pkt, 14); > + ip = (odp_ipv4hdr_t *)(buf + 14); > + ip->dst_addr = odp_cpu_to_be_32(scan_ip(dstip)); > + ip->src_addr = odp_cpu_to_be_32(scan_ip(srcip)); > + ip->ver_ihl = ODP_IPV4<<4|5; > + ip->tot_len = odp_cpu_to_be_16(pksize + 8 + 20); > + ip->proto = ODP_IPPROTO_UDP; > + ip->id = odp_cpu_to_be_16(pcount++); > + compute_ip_checksum(ip); > + //udp > + udp = (odp_udphdr_t *) (buf + 14 + 20); > + udp->src_port = 0; > + udp->dst_port = 0; > + udp->length = odp_cpu_to_be_16(pksize + 8); > + udp->chksum = 0; > + compute_udp_checksum(ip, (unsigned short *)udp); > + > + odp_packet_set_len(pkt,pksize + 8 + 20 + 14); > +} > + > +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; > + struct icmphdr *icmp; > + struct timeval *tval; > + > + buf = odp_buffer_addr(obuf); > + if(buf == NULL) > + return; > + max = odp_buffer_size(obuf); > + if(max <= 0) > + return; > + > + memset(buf, 0, max); > + pksize = 56; //set icmp size 56 > + pkt = odp_packet_from_buffer(obuf); > + //ether > + odp_packet_set_l2_offset(pkt, 0); > + eth = (odp_ethhdr_t *)buf; > + scan_mac(dstmac,(char *)eth->dst.addr); > + scan_mac(srcmac,(char *)eth->src.addr); > + eth->type = odp_cpu_to_be_16 (ODP_ETHTYPE_IPV4); > + //ip > + odp_packet_set_l3_offset(pkt, 14); > + ip = (odp_ipv4hdr_t *)(buf + 14); > + ip->dst_addr = odp_cpu_to_be_32(scan_ip(dstip)); > + ip->src_addr = odp_cpu_to_be_32(scan_ip(srcip)); > + ip->ver_ihl = ODP_IPV4<<4|5; > + ip->tot_len = odp_cpu_to_be_16(56 + 8 + 20); > + ip->proto = ODP_IPPROTO_ICMP; > + ip->id = odp_cpu_to_be_16(pcount++); > + compute_ip_checksum(ip); > + //icmp > + icmp = (struct icmphdr *) (buf + 14 + 20); > + icmp->type = 8; //Echo Request > + icmp->code = 0; > + icmp->id = odp_cpu_to_be_16(pcount - 1); > + icmp->sequence = odp_cpu_to_be_16(pcount - 1); > + tval = (struct timeval *)(buf + 14 + 20 + 8); > + gettimeofday(tval,NULL); > + icmp->checksum = 0; > + icmp->checksum = compute_checksum((unsigned short *)icmp, 64); > + > + odp_packet_set_len(pkt,56 + 8 + 20 + 14); > +} > + > + > + > +/** > + * Packet IO loopback worker thread using ODP queues > + * > + * @param arg thread arguments of type 'thread_args_t *' > + */ > +static void *pktio_queue_thread(void *arg) > +{ > + int thr; > + odp_buffer_pool_t pkt_pool; > + odp_pktio_t pktio; > + thread_args_t *thr_args; > + odp_queue_t outq_def; > + 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; > + > + if(mode == 1&& thr_args->mode != 2) > + sleep(1); //wait receiver ok; > + printf("Pktio thread [%02i] starts, pktio_dev:%s\n", thr, > + thr_args->pktio_dev); > + > + /* Lookup the packet pool */ > + pkt_pool = odp_buffer_pool_lookup("packet_pool"); > + if (pkt_pool == ODP_BUFFER_POOL_INVALID) { > + ODP_ERR(" [%02i] Error: pkt_pool not found\n", thr); > + return NULL; > + } > + > + /* Open a packet IO instance for this thread */ > + sock_params->type = ODP_PKTIO_TYPE_SOCKET; > + 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; > + } > + > + if (thr_args->mode == 0 || thr_args->mode == 1) { > + 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; > + } > + > + for(;;) { > + int err; > + buf = odp_buffer_alloc(pkt_pool); > + if (!odp_buffer_is_valid(buf)) { > + ODP_ERR(" [%i] alloc_single failed\n", thr); > + return NULL; > + } > + > + if(thr_args->mode == 0) > + pack_udp_pkt(buf); > + else > + pack_icmp_pkt(buf); > + > + err = odp_queue_enq(outq_def, buf); > + total++; > + if (err != 0) { > + printf("send pkt err!\n"); > + return NULL; > + } > + if(interval != 0) { //flood mode will not print msg > + printf("Generator send pkt no:%llu seq %d size:%d\n", total,pcount - 1, pksize); > + usleep(interval * 1000); > + } else { > + printf("Generator send pkt no:%llu seq %d size:%d\r", total,pcount - 1, pksize); > + } > + if (number != -1 && (int)total >= number) { > + break; > + } > + > + } > + //if timeout >= 0; > + while(mode == 1 && timeout >= 0) { > + if(icmpcount >= number) > + break; > + sleep(1); > + timeout--; > + } > + //print info: > + if(mode == 0) { > + printf("Total send:%llu\n",total); > + } else if (mode == 1) { > + printf("Total send:%llu,total receiver %d\n",total,icmpcount); > + } > + exit(0); > + > + } else if(thr_args->mode == 2) { > + 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; > + } > + > + for (;;) { > + /* Use schedule to get buf from any input queue */ > + buf = odp_schedule(NULL); > + > + pkt = odp_packet_from_buffer(buf); > + /* Drop packets with errors */ > + if (odp_unlikely(drop_err_pkts(&pkt, 1) == 0)) { > + ODP_ERR("Drop frame\n"); > + continue; > + } > + > + /* Swap Eth MACs and possibly IP-addrs before sending back */ > + print_pkts(&pkt, 1); > + > + odp_packet_free(pkt); > + > + } > + > + } > + > + return arg; > +} > + > +/** > + * Swap eth src<->dst and IP src<->dst addresses > + * > + * @param pkt_tbl Array of packets > + * @param len Length of pkt_tbl[] > + */ > + > +static void print_pkts(odp_packet_t pkt_tbl[], unsigned len) > +{ > + odp_packet_t pkt; > + char *buf; > + odp_ipv4hdr_t *ip; > + odp_udphdr_t *udp; > + struct icmphdr *icmp; > + struct timeval tvrecv; > + struct timeval *tvsend; > + double rtt; > + unsigned i; > + char msg[1024]; > + int rlen = 0; > + FILE *stream; > + for (i = 0; i < len; ++i) { > + pkt = pkt_tbl[i]; > + memset(msg, 0, 1024); > + // print ip header > + if(odp_packet_inflag_ipv4(pkt)) { > + ipcount++; > + 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)); > + //ip = (odp_ipv4hdr_t *)odp_packet_l3(pkt); > + rlen += sprintf(msg + rlen,"id %d ",odp_be_to_cpu_16(ip->id)); > + > + //udp > + if(ip->proto == ODP_IPPROTO_UDP) { > + udpcount++; > + udp = (odp_udphdr_t *)(buf + odp_packet_l4_offset(pkt)); > + rlen += sprintf(msg + rlen," UDP payload %d ",odp_be_to_cpu_16(udp->length) - 8); > + } > + > + //icmp > + if(ip->proto == ODP_IPPROTO_ICMP) { > + icmp = (struct icmphdr *)(buf + odp_packet_l4_offset(pkt)); > + if(icmp->type == 0) { > + icmpcount++; > + tvsend = (struct timeval *)(buf + odp_packet_l4_offset(pkt) + 8); > + gettimeofday(&tvrecv,NULL); > + tv_sub(&tvrecv,tvsend); > + rtt = tvrecv.tv_sec*1000 + tvrecv.tv_usec/1000; > + rlen += sprintf(msg + rlen, "ICMP seq %d time %.1f ",odp_be_to_cpu_16(icmp->sequence), rtt); > + if(mode == 1) //ping mode > + printf("%s\n",msg); > + } > + > + } > + if (mode == 2) //receiver mode > + printf("%s\n",msg); > + stream = fopen( "/tmp/recv.log", "a" ); > + fprintf(stream, "Receive pkt NO:%d\n",odp_be_to_cpu_16(ip->id)); > + fclose( stream ); > + } > + > + } > +} > + > +/** > + * 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; > + > + /* Init ODP before calling anything else */ > + if (odp_init_global()) { > + ODP_ERR("Error: ODP global init failed.\n"); > + exit(EXIT_FAILURE); > + } > + > + /* 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); > + > + /* 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 (mode == 1) > + num_workers = 2; > + else > + num_workers = 1; > + > + if (mode == 0) { > + printf("Work mode: send udp packets\n\n"); > + } else if (mode == 1) { > + printf("Work mode: ping\n\n"); > + } else if (mode == 2) { > + printf("Work mode: receive ip packets\n\n"); > + } else { > + printf("Wrong mode\n"); > + exit(EXIT_FAILURE); > + } > + for (i = 0; i < num_workers; ++i) { > + void *(*thr_run_func) (void *); > + int 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 = mode; > + if(i == 1) > + args->thread[i].mode = 2; > + thr_run_func = pktio_queue_thread; > + /* > + * 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, i, 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 > + */ > +#pragma GCC diagnostic push // require GCC 4.6 > +#pragma GCC diagnostic ignored "-Wcast-qual" > +#pragma GCC diagnostic ignored "-Werror" > +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'}, /* return 'i' */ > + {"srcmac", required_argument, NULL, 'a'}, /* return 'm' */ > + {"dstmac", required_argument, NULL, 'b'}, /* return 'm' */ > + {"srcip", required_argument, NULL, 'c'}, /* return 'm' */ > + {"dstip", required_argument, NULL, 'd'}, /* return 'm' */ > + {"packetsize", required_argument, NULL, 's'}, /* return 'h' */ > + {"mode", required_argument, NULL, 'm'}, > + {"count", required_argument, NULL, 'n'}, > + {"timeout", required_argument, NULL, 't'}, > + {"interval", required_argument, NULL, 'i'}, /* return 'h' */ > + {"help", no_argument, NULL, 'h'}, /* return 'h' */ > + {NULL, 0, NULL, 0} > + }; > + > + > + while (1) { > + opt = getopt_long(argc, argv, "+I:a:b:c:d:s:i:m:n:t:h", longopts, &long_index); > + > + if (opt == -1) > + break; /* No more options */ > + > + switch (opt) { > + /* 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 'a': > + strcpy(srcmac, optarg); > + break; > + case 'b': > + strcpy(dstmac, optarg); > + break; > + > + case 'c': > + strcpy(srcip, optarg); > + break; > + > + case 'd': > + strcpy(dstip, optarg); > + break; > + case 's': > + pksize = atoi(optarg); > + if(pksize > SHM_PKT_POOL_BUF_SIZE - 14 - 20 - 8) { > + printf("the pksize is too big!\n"); > + exit(EXIT_FAILURE); > + } > + break; > + case 'm': > + if(optarg[0] == 'u') { > + mode = 0; > + } else if (optarg[0] == 'p') { > + mode = 1; > + } else if (optarg[0] == 'r') { > + mode = 2; > + } else { > + printf("wrong mode!\n"); > + exit(EXIT_FAILURE); > + } > + break; > + case 'n': > + number = atoi(optarg); > + break; > + case 't': > + timeout = atoi(optarg); > + break; > + case 'i': > + interval = atoi(optarg); > + if(interval <= 200 && geteuid() != 0) { > + printf("Only super-user may set interval to values less 0.2 seconds.\n"); > + exit(EXIT_FAILURE); > + } > + break; > + case 'h': > + usage(argv[0]); > + exit(EXIT_SUCCESS); > + break; > + > + default: > + break; > + } > + } > + > + > + optind = 1; /* reset 'extern optind' from the getopt lib */ > +} > +#pragma GCC diagnostic pop > +/** > + * 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 freq (hz): %"PRIu64"\n" > + "Cache line size: %i\n" > + "Core count: %i\n" > + "\n", > + odp_version_api_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\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 veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m u\n" > + " 2.receive udp packets\n" > + " 3.work likes ping\n" > + " odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m p\n" > + "\n" > + "Mandatory OPTIONS:\n" > + " -I, --interface Eth interfaces (comma-separated, no spaces)\n" > + " -a, --srcmac src mac adddress\n" > + " -b, --dstmac dst mac adddress\n" > + " -c, --srcip src ip adddress\n" > + " -d, --dstip dst ip adddress\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 floord mode\n" > + "\n" > + "Optional OPTIONS\n" > + " -h, --help Display help and exit.\n" > + "\n", NO_PATH(progname), NO_PATH(progname) > + ); > +} > +/** > + * Drop packets which input parsing marked as containing errors. > + * > + * Frees packets with error and modifies pkt_tbl[] to only contain packets with > + * no detected errors. > + * > + * @param pkt_tbl Array of packet > + * @param len Length of pkt_tbl[] > + * > + * @return Number of packets with no detected error > + */ > +static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len) > +{ > + odp_packet_t pkt; > + unsigned pkt_cnt = len; > + unsigned i, j; > + > + for (i = 0, j = 0; i < len; ++i) { > + pkt = pkt_tbl[i]; > + > + if (odp_unlikely(odp_packet_error(pkt))) { > + odp_packet_free(pkt); /* Drop */ > + pkt_cnt--; > + } else if (odp_unlikely(i != j++)) { > + pkt_tbl[j] = pkt; > + } > + } > + > + return pkt_cnt; > +} > + > +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; > + } > +} > -- > 1.7.9.5 > > -- > You received this message because you are subscribed to the Google Groups "LNG ODP Sub-team - lng-odp@linaro.org" group. > To unsubscribe from this group and stop receiving emails from it, send an email to lng-odp+unsubscribe@linaro.org. > To post to this group, send email to lng-odp@linaro.org. > Visit this group at http://groups.google.com/a/linaro.org/group/lng-odp/. > To view this discussion on the web visit https://groups.google.com/a/linaro.org/d/msgid/lng-odp/1395389350-12912-1-git-send-email-weilong.chen%40linaro.org. > For more options, visit https://groups.google.com/a/linaro.org/d/optout.
On Fri, Mar 21, 2014 at 08:09:10AM +0000, Weilong Chen wrote: > odp_generator can send/receive udp packets, or works like ping. Some comments below. I've ignored style issues assuming you'll run this through checkpatch before resending. I am also assuming that this tool is intended to evolve over time and will become a more general purpose and high performance tool, so my comments reflect that. > Work mode: > 1.send udp packets > odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m u > 2.receive udp packets > odp_generator -I eth1 -r > 3.work likes ping > odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m p > The short names here (a,b,c,d) don't match their purpose very well, it's probably better to stick with the long names. > Signed-off-by: Weilong Chen <weilong.chen@linaro.org> > --- > .gitignore | 1 + > test/Makefile | 3 + > test/generator/Makefile | 46 +++ > test/generator/odp_generator.c | 847 ++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 897 insertions(+) > create mode 100644 test/generator/Makefile > create mode 100644 test/generator/odp_generator.c > > diff --git a/.gitignore b/.gitignore > index 53454a5..91055bd 100644 > --- a/.gitignore > +++ b/.gitignore > @@ -14,3 +14,4 @@ test/packet_netmap/odp_packet > test/api_test/odp_atomic > test/api_test/odp_shm > test/api_test/odp_ring > +test/generator/odp_generator > diff --git a/test/Makefile b/test/Makefile > index 2ff7a4c..771b3f4 100644 > --- a/test/Makefile > +++ b/test/Makefile > @@ -9,6 +9,7 @@ all: > $(MAKE) -C example > $(MAKE) -C packet > $(MAKE) -C packet_netmap > + $(MAKE) -C generator > > .PHONY: clean > clean: > @@ -16,6 +17,7 @@ clean: > $(MAKE) -C example clean > $(MAKE) -C packet clean > $(MAKE) -C packet_netmap clean > + $(MAKE) -C generator clean > > .PHONY: install > install: > @@ -23,3 +25,4 @@ install: > $(MAKE) -C example install > $(MAKE) -C packet install > $(MAKE) -C packet_netmap install > + $(MAKE) -C generator install > diff --git a/test/generator/Makefile b/test/generator/Makefile > new file mode 100644 > index 0000000..350d2e4 > --- /dev/null > +++ b/test/generator/Makefile > @@ -0,0 +1,46 @@ > +# Copyright (c) 2013, Linaro Limited 2014 > +# 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..0ec855b > --- /dev/null > +++ b/test/generator/odp_generator.c > @@ -0,0 +1,847 @@ > +/* Copyright (c) 2013, Linaro Limited 2014 > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > +/** > + * @file > + * > + * @example odp_generator.c ODP loopback demo application > + */ This deserves more of a comment. What does the application do and how/why do I use it?.. Can the same instance generate and receive packets or do I need to run multiple instances? Can I run it on multiple cores? Can it send/receive on multiple interfaces? What sort of performance can I expect? (I know this is heavily implementation dependant, but is this intended to achieve close to maximum potential or is it just a gentle ping?).. etc. > + > +#include <stdlib.h> > +#include <string.h> > +#include <getopt.h> > +#include <unistd.h> > +#include <stdio.h> > +#include<sys/time.h> > + > +#include <odp.h> > +#include <helper/odp_packet_helper.h> > +#include <helper/odp_linux.h> > +#include <helper/odp_eth.h> > +#include <helper/odp_ip.h> > +#include <helper/odp_udp.h> > +#include <odp_packet_io.h> > + > + > +#define SHM_PKT_POOL_SIZE (512*2048) > +#define SHM_PKT_POOL_BUF_SIZE 1856 > + > + > +#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)) This appears in every application now, it should go in a helper. > +/** > + * Parsed command line application arguments > + */ > +typedef struct { > + 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 */ > +} appl_args_t; > + > +/** > + * Thread specific arguments > + */ > +typedef struct { > + char *pktio_dev; /**< Interface name to use */ > + odp_buffer_pool_t pool; /**< Buffer pool for packet IO */ > + int mode; /**< 0 send, 1 receive */ > +} thread_args_t; > + > +/** > + * Grouping of both parsed CL args and thread specific args - alloc together > + */ > +#define MAX_WORKERS 1 > +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 */ > +void tv_sub(struct timeval *recvtime,struct timeval *sendtime); > +static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len); > +static void print_pkts(odp_packet_t pkt_tbl[], unsigned len); > +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); > +unsigned int scan_ip(char *ip); > +int scan_mac(char *in,char *des); > +void compute_ip_checksum(odp_ipv4hdr_t *iphdrp); > +void compute_udp_checksum(odp_ipv4hdr_t *pIph, unsigned short *ipPayload); > + > +/* args */ > +char srcip[20]; > +char dstip[20]; > +char srcmac[20]; > +char dstmac[20]; > +int pksize = 0; > +int interval = 1 * 1000; > +int number = -1; //packets to send > +int timeout = -1; //timeout seconds > +int mode; //0 udp, 1 icmp, 2 r; Should be an enum and have a more descriptive name, and all of these args should go into appl_args_t. > +int ipcount; > +int udpcount; > +int icmpcount; > +unsigned long long total; Similarly could do with a counters structure. I note that there's no provision here to cope with updating counters from multiple threads, but given that this implementation is currently limited to a single thread (per receiver/transmitter) I guess that's out of scope for now. > +struct icmphdr { > + u_int8_t type; /* message type */ > + u_int8_t code; /* type sub-code */ > + u_int16_t checksum; > + u_int16_t id; > + u_int16_t sequence; > +}; Put this in an odp_icmp.h helper as per odp_udp.h and use uint16be_t. Also use chksum rather than checksum, to match the others. > + > +/* parser ip */ > +unsigned int scan_ip(char *ip) > +{ > + int part1,part2,part3,part4; > + unsigned int ipi; > + > + sscanf(ip,"%d.%d.%d.%d",&part1,&part2,&part3,&part4); > + ipi = 0; > + ipi = part1 <<24 | part2 << 16| part3 << 8 | part4 ; > + return ipi; > +} > + > +/* parser mac */ > +int scan_mac(char *in,char *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[i] = mac[i]; > + } > + > + return field; > +} int scan_mac(char *in, uint8_t *mac) { return sscanf(in, "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); } And use odp_ethaddr_t.addr > + > +static unsigned short pcount; > + > +/* Compute checksum for count bytes starting at addr, using one's complement of one's complement sum*/ > +static unsigned short compute_checksum(unsigned short *addr, unsigned int count) > +{ > + register unsigned long sum = 0; > + while (count > 1) { > + sum += * addr++; > + count -= 2; > + } > + //if any bytes left, pad the bytes and add > + if(count > 0) { > + sum += ((*addr)&odp_cpu_to_be_16(0xFF00)); > + } > + //Fold sum to 16 bits: add carrier to result > + while (sum>>16) { > + sum = (sum & 0xffff) + (sum >> 16); > + } > + //one's complement > + sum = ~sum; > + return ((unsigned short)sum); > +} > + > +/* set ip checksum of a given ip header*/ > +void compute_ip_checksum(odp_ipv4hdr_t *iphdrp) > +{ > + iphdrp->chksum = 0; > + iphdrp->chksum = compute_checksum((unsigned short*)iphdrp, iphdrp->ver_ihl<<2); > +} > +void compute_udp_checksum(odp_ipv4hdr_t *pIph, unsigned short *ipPayload) > +{ > + register unsigned long sum = 0; > + odp_udphdr_t *udphdrp = (odp_udphdr_t *)(ipPayload); > + unsigned short udpLen = odp_cpu_to_be_16(udphdrp->length); > + //the source ip > + sum += (pIph->src_addr>>16)&0xFFFF; > + sum += (pIph->src_addr)&0xFFFF; > + //the dest ip > + sum += (pIph->dst_addr>>16)&0xFFFF; > + sum += (pIph->dst_addr)&0xFFFF; > + sum += odp_cpu_to_be_16(ODP_IPPROTO_UDP); > + //the length > + sum += udphdrp->length; > + > + //initialize checksum to 0 > + udphdrp->chksum = 0; > + while (udpLen > 1) { > + sum += * ipPayload++; > + udpLen -= 2; > + } > + //if any bytes left, pad the bytes and add > + if(udpLen > 0) { > + sum += ((*ipPayload)&odp_cpu_to_be_16(0xFF00)); > + } > + //Fold sum to 16 bits: add carrier to result > + //printf("add carrier\n"); > + while (sum>>16) { > + sum = (sum & 0xffff) + (sum >> 16); > + } > + //printf("one's complement\n"); > + sum = ~sum; > + //set computation result > + udphdrp->chksum = ((unsigned short)sum == 0x0000)?0xFFFF:(unsigned short)sum; > +} The checksum calculations should use odp_chksum(). > + > +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; > + > + buf = odp_buffer_addr(obuf); > + if(buf == NULL) > + return; > + max = odp_buffer_size(obuf); > + if(max <= 0) > + return; > + > + memset(buf, 0, max); memset'ing the entire buffer isn't needed. > + pkt = odp_packet_from_buffer(obuf); > + //ether > + odp_packet_set_l2_offset(pkt, 0); > + eth = (odp_ethhdr_t *)buf; > + scan_mac(dstmac,(char *)eth->dst.addr); > + scan_mac(srcmac,(char *)eth->src.addr); This is using sscanf to convert from the strings provided on the command line for every packet!?.. do it once and store the value. > + eth->type = odp_cpu_to_be_16 (ODP_ETHTYPE_IPV4); > + //ip > + odp_packet_set_l3_offset(pkt, 14); > + ip = (odp_ipv4hdr_t *)(buf + 14); Use ODP_ETHHDR_LEN. There are lots of other magic numbers used in this patch that should be changed too. > + ip->dst_addr = odp_cpu_to_be_32(scan_ip(dstip)); > + ip->src_addr = odp_cpu_to_be_32(scan_ip(srcip)); Same comment as above, don't use scan_ip here. > + ip->ver_ihl = ODP_IPV4<<4|5; > + ip->tot_len = odp_cpu_to_be_16(pksize + 8 + 20); > + ip->proto = ODP_IPPROTO_UDP; > + ip->id = odp_cpu_to_be_16(pcount++); > + compute_ip_checksum(ip); > + //udp > + udp = (odp_udphdr_t *) (buf + 14 + 20); > + udp->src_port = 0; > + udp->dst_port = 0; > + udp->length = odp_cpu_to_be_16(pksize + 8); > + udp->chksum = 0; > + compute_udp_checksum(ip, (unsigned short *)udp); > + > + odp_packet_set_len(pkt,pksize + 8 + 20 + 14); > +} > + > +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; > + struct icmphdr *icmp; > + struct timeval *tval; > + > + buf = odp_buffer_addr(obuf); > + if(buf == NULL) > + return; > + max = odp_buffer_size(obuf); > + if(max <= 0) > + return; > + > + memset(buf, 0, max); don't memset the entire buffer > + pksize = 56; //set icmp size 56 > + pkt = odp_packet_from_buffer(obuf); > + //ether > + odp_packet_set_l2_offset(pkt, 0); > + eth = (odp_ethhdr_t *)buf; > + scan_mac(dstmac,(char *)eth->dst.addr); > + scan_mac(srcmac,(char *)eth->src.addr); don't use scan_mac here > + eth->type = odp_cpu_to_be_16 (ODP_ETHTYPE_IPV4); > + //ip > + odp_packet_set_l3_offset(pkt, 14); > + ip = (odp_ipv4hdr_t *)(buf + 14); > + ip->dst_addr = odp_cpu_to_be_32(scan_ip(dstip)); > + ip->src_addr = odp_cpu_to_be_32(scan_ip(srcip)); don't use scan_ip here > + ip->ver_ihl = ODP_IPV4<<4|5; > + ip->tot_len = odp_cpu_to_be_16(56 + 8 + 20); > + ip->proto = ODP_IPPROTO_ICMP; > + ip->id = odp_cpu_to_be_16(pcount++); > + compute_ip_checksum(ip); > + //icmp > + icmp = (struct icmphdr *) (buf + 14 + 20); > + icmp->type = 8; //Echo Request > + icmp->code = 0; > + icmp->id = odp_cpu_to_be_16(pcount - 1); > + icmp->sequence = odp_cpu_to_be_16(pcount - 1); > + tval = (struct timeval *)(buf + 14 + 20 + 8); > + gettimeofday(tval,NULL); gettimeofday causes a syscall. This should be changed to use an ODP timer API once one exists. > + icmp->checksum = 0; > + icmp->checksum = compute_checksum((unsigned short *)icmp, 64); > + > + odp_packet_set_len(pkt,56 + 8 + 20 + 14); > +} > + > + > + > +/** > + * Packet IO loopback worker thread using ODP queues > + * > + * @param arg thread arguments of type 'thread_args_t *' > + */ > +static void *pktio_queue_thread(void *arg) > +{ > + int thr; > + odp_buffer_pool_t pkt_pool; > + odp_pktio_t pktio; > + thread_args_t *thr_args; > + odp_queue_t outq_def; > + 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; > + > + if(mode == 1&& thr_args->mode != 2) > + sleep(1); //wait receiver ok; Don't sleep, use a barrier. > + printf("Pktio thread [%02i] starts, pktio_dev:%s\n", thr, > + thr_args->pktio_dev); > + > + /* Lookup the packet pool */ > + pkt_pool = odp_buffer_pool_lookup("packet_pool"); > + if (pkt_pool == ODP_BUFFER_POOL_INVALID) { > + ODP_ERR(" [%02i] Error: pkt_pool not found\n", thr); > + return NULL; > + } > + > + /* Open a packet IO instance for this thread */ > + sock_params->type = ODP_PKTIO_TYPE_SOCKET; > + 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; > + } > + > + if (thr_args->mode == 0 || thr_args->mode == 1) { Different modes of operation should be factored out into separate functions for clarity, perhaps it would be clearer to use a different thr_run_func for receiver and transmitter. Again the use of magic numbers and the mix of application mode vs thread mode doesn't help understand what's going on. > + 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; > + } > + > + for(;;) { > + int err; > + buf = odp_buffer_alloc(pkt_pool); > + if (!odp_buffer_is_valid(buf)) { > + ODP_ERR(" [%i] alloc_single failed\n", thr); > + return NULL; So this thread dies.. what happens to the other(s)? > + } > + > + if(thr_args->mode == 0) > + pack_udp_pkt(buf); > + else > + pack_icmp_pkt(buf); > + > + err = odp_queue_enq(outq_def, buf); > + total++; > + if (err != 0) { > + printf("send pkt err!\n"); Use ODP_ERR > + return NULL; > + } > + if(interval != 0) { //flood mode will not print msg But the else has exactly the same printf.. > + printf("Generator send pkt no:%llu seq %d size:%d\n", total,pcount - 1, pksize); > + usleep(interval * 1000); Again, shouldn't be sleeping here, you should instead kick off a timer to generate an event when the next packet needs to be sent. I'm not sure of the status of the current timer API so it might not be possible to make this change yet. > + } else { > + printf("Generator send pkt no:%llu seq %d size:%d\r", total,pcount - 1, pksize); > + } > + if (number != -1 && (int)total >= number) { > + break; > + } You have an unsigned long long counter which is only used for checking that it's within the range on a signed int, that doesn't make a lot of sense. > + > + } > + //if timeout >= 0; > + while(mode == 1 && timeout >= 0) { > + if(icmpcount >= number) > + break; > + sleep(1); > + timeout--; > + } I'm confused as to what this block is achieving. It certainly doesn't seem to be using timeout in the way that is suggested in the help text. It looks like the intended purpose isn't supported at all. > + //print info: > + if(mode == 0) { > + printf("Total send:%llu\n",total); > + } else if (mode == 1) { > + printf("Total send:%llu,total receiver %d\n",total,icmpcount); > + } > + exit(0); Remove this exit, just allow the function to return. > + > + } else if(thr_args->mode == 2) { > + 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; > + } > + > + for (;;) { > + /* Use schedule to get buf from any input queue */ > + buf = odp_schedule(NULL); > + > + pkt = odp_packet_from_buffer(buf); > + /* Drop packets with errors */ > + if (odp_unlikely(drop_err_pkts(&pkt, 1) == 0)) { > + ODP_ERR("Drop frame\n"); > + continue; > + } > + > + /* Swap Eth MACs and possibly IP-addrs before sending back */ > + print_pkts(&pkt, 1); Comment is wrong. > + > + odp_packet_free(pkt); > + > + } > + > + } > + > + return arg; > +} > + > +/** > + * Swap eth src<->dst and IP src<->dst addresses Comment is wrong. > + * > + * @param pkt_tbl Array of packets > + * @param len Length of pkt_tbl[] > + */ > + > +static void print_pkts(odp_packet_t pkt_tbl[], unsigned len) > +{ > + odp_packet_t pkt; > + char *buf; > + odp_ipv4hdr_t *ip; > + odp_udphdr_t *udp; > + struct icmphdr *icmp; > + struct timeval tvrecv; > + struct timeval *tvsend; > + double rtt; > + unsigned i; > + char msg[1024]; > + int rlen = 0; rlen should be reset inside the loop to avoid an overflow when len>1 (though actually the caller has hard coded len to 1 so it can't happen as it is). > + FILE *stream; > + for (i = 0; i < len; ++i) { > + pkt = pkt_tbl[i]; > + memset(msg, 0, 1024); don't need to memset the entire msg, if you're being cautious the most you need is: msg[0] = '\0'; > + // print ip header > + if(odp_packet_inflag_ipv4(pkt)) { > + ipcount++; > + 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)); > + //ip = (odp_ipv4hdr_t *)odp_packet_l3(pkt); > + rlen += sprintf(msg + rlen,"id %d ",odp_be_to_cpu_16(ip->id)); > + > + //udp > + if(ip->proto == ODP_IPPROTO_UDP) { > + udpcount++; > + udp = (odp_udphdr_t *)(buf + odp_packet_l4_offset(pkt)); > + rlen += sprintf(msg + rlen," UDP payload %d ",odp_be_to_cpu_16(udp->length) - 8); > + } > + > + //icmp > + if(ip->proto == ODP_IPPROTO_ICMP) { > + icmp = (struct icmphdr *)(buf + odp_packet_l4_offset(pkt)); > + if(icmp->type == 0) { > + icmpcount++; > + tvsend = (struct timeval *)(buf + odp_packet_l4_offset(pkt) + 8); > + gettimeofday(&tvrecv,NULL); Same comment as previous re gettimeofday > + tv_sub(&tvrecv,tvsend); > + rtt = tvrecv.tv_sec*1000 + tvrecv.tv_usec/1000; > + rlen += sprintf(msg + rlen, "ICMP seq %d time %.1f ",odp_be_to_cpu_16(icmp->sequence), rtt); > + if(mode == 1) //ping mode > + printf("%s\n",msg); > + } > + > + } > + if (mode == 2) //receiver mode > + printf("%s\n",msg); I don't really like the way msg is constructed, looks like it could be constructed and then not used. Splitting out the ICMP and UDP stuff would simplify things. > + stream = fopen( "/tmp/recv.log", "a" ); > + fprintf(stream, "Receive pkt NO:%d\n",odp_be_to_cpu_16(ip->id)); > + fclose( stream ); Hrm.. I think we need to sort out a logging framework as this sort of thing really shouldn't be here. > + } > + > + } > +} > + > +/** > + * 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; > + > + /* Init ODP before calling anything else */ > + if (odp_init_global()) { > + ODP_ERR("Error: ODP global init failed.\n"); > + exit(EXIT_FAILURE); > + } > + > + /* 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); > + > + /* 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 (mode == 1) > + num_workers = 2; > + else > + num_workers = 1; > + This num_workers pegging is a bit restrictive. It would obviously be good to be able to use more cores (would need rework of the globals) > + if (mode == 0) { > + printf("Work mode: send udp packets\n\n"); > + } else if (mode == 1) { > + printf("Work mode: ping\n\n"); > + } else if (mode == 2) { > + printf("Work mode: receive ip packets\n\n"); > + } else { > + printf("Wrong mode\n"); > + exit(EXIT_FAILURE); > + } > + for (i = 0; i < num_workers; ++i) { > + void *(*thr_run_func) (void *); > + int 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 = mode; > + if(i == 1) > + args->thread[i].mode = 2; > + thr_run_func = pktio_queue_thread; > + /* > + * 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, i, 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 > + */ > +#pragma GCC diagnostic push // require GCC 4.6 > +#pragma GCC diagnostic ignored "-Wcast-qual" > +#pragma GCC diagnostic ignored "-Werror" Why is this needed? > +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'}, /* return 'i' */ > + {"srcmac", required_argument, NULL, 'a'}, /* return 'm' */ > + {"dstmac", required_argument, NULL, 'b'}, /* return 'm' */ > + {"srcip", required_argument, NULL, 'c'}, /* return 'm' */ > + {"dstip", required_argument, NULL, 'd'}, /* return 'm' */ > + {"packetsize", required_argument, NULL, 's'}, /* return 'h' */ > + {"mode", required_argument, NULL, 'm'}, > + {"count", required_argument, NULL, 'n'}, > + {"timeout", required_argument, NULL, 't'}, > + {"interval", required_argument, NULL, 'i'}, /* return 'h' */ > + {"help", no_argument, NULL, 'h'}, /* return 'h' */ > + {NULL, 0, NULL, 0} > + }; The "return '?'" comments are not correct and seem a bit pointless. > + > + > + while (1) { > + opt = getopt_long(argc, argv, "+I:a:b:c:d:s:i:m:n:t:h", longopts, &long_index); > + > + if (opt == -1) > + break; /* No more options */ > + > + switch (opt) { > + /* 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; There's an identical chunk in odp_example_pktio[_netmap].c so this should be put in a helper. > + case 'a': > + strcpy(srcmac, optarg); > + break; > + case 'b': > + strcpy(dstmac, optarg); > + break; > + > + case 'c': > + strcpy(srcip, optarg); > + break; > + > + case 'd': > + strcpy(dstip, optarg); > + break; > + case 's': > + pksize = atoi(optarg); > + if(pksize > SHM_PKT_POOL_BUF_SIZE - 14 - 20 - 8) { There are #defines for ODP_ETHHDR_LEN and ODP_IPV4HDR_LEN already. Although I think this check should be moved to a later point because you don't (necessarily) know what protocol you're using, the 8 here could be either ICMP header length or UDP header length (ok they are both 8 bytes, but that's a coincidence). > + printf("the pksize is too big!\n"); > + exit(EXIT_FAILURE); > + } > + break; > + case 'm': > + if(optarg[0] == 'u') { > + mode = 0; > + } else if (optarg[0] == 'p') { > + mode = 1; > + } else if (optarg[0] == 'r') { > + mode = 2; named enums needed here. > + } else { > + printf("wrong mode!\n"); > + exit(EXIT_FAILURE); > + } > + break; > + case 'n': > + number = atoi(optarg); > + break; > + case 't': > + timeout = atoi(optarg); > + break; > + case 'i': > + interval = atoi(optarg); > + if(interval <= 200 && geteuid() != 0) { > + printf("Only super-user may set interval to values less 0.2 seconds.\n"); > + exit(EXIT_FAILURE); > + } > + break; > + case 'h': > + usage(argv[0]); > + exit(EXIT_SUCCESS); > + break; > + > + default: > + break; > + } > + } > + > + > + optind = 1; /* reset 'extern optind' from the getopt lib */ > +} > +#pragma GCC diagnostic pop > +/** > + * 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 freq (hz): %"PRIu64"\n" > + "Cache line size: %i\n" > + "Core count: %i\n" > + "\n", > + odp_version_api_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\n"); > + fflush(NULL); > +} print_info should go into a helper. > + > +/** > + * 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 veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m u\n" > + " 2.receive udp packets\n" > + " 3.work likes ping\n" > + " odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m p\n" > + "\n" > + "Mandatory OPTIONS:\n" > + " -I, --interface Eth interfaces (comma-separated, no spaces)\n" > + " -a, --srcmac src mac adddress\n" > + " -b, --dstmac dst mac adddress\n" > + " -c, --srcip src ip adddress\n" > + " -d, --dstip dst ip adddress\n" s/adddress/address/ > + " -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 floord mode\n" s/floord/flood/ > + "\n" > + "Optional OPTIONS\n" > + " -h, --help Display help and exit.\n" > + "\n", NO_PATH(progname), NO_PATH(progname) > + ); > +} > +/** > + * Drop packets which input parsing marked as containing errors. > + * > + * Frees packets with error and modifies pkt_tbl[] to only contain packets with > + * no detected errors. > + * > + * @param pkt_tbl Array of packet > + * @param len Length of pkt_tbl[] > + * > + * @return Number of packets with no detected error > + */ > +static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len) > +{ > + odp_packet_t pkt; > + unsigned pkt_cnt = len; > + unsigned i, j; > + > + for (i = 0, j = 0; i < len; ++i) { > + pkt = pkt_tbl[i]; > + > + if (odp_unlikely(odp_packet_error(pkt))) { > + odp_packet_free(pkt); /* Drop */ > + pkt_cnt--; > + } else if (odp_unlikely(i != j++)) { > + pkt_tbl[j] = pkt; > + } > + } > + > + return pkt_cnt; > +} > + The above function is a duplicate of the one in odp_example_pktio.c, it should be moved to a helper file. > +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; > + } > +}
Stuart, there are already a number of cards to increase this tools utility, and feature requests are eagerly sought, but this is just the first evolution beyond the demo ping app. I think it should form a significant role in our testing when complete. On 21 March 2014 10:47, Stuart Haslam <stuart.haslam@arm.com> wrote: > On Fri, Mar 21, 2014 at 08:09:10AM +0000, Weilong Chen wrote: > > odp_generator can send/receive udp packets, or works like ping. > > Some comments below. I've ignored style issues assuming you'll run this > through checkpatch before resending. > > I am also assuming that this tool is intended to evolve over time and > will become a more general purpose and high performance tool, so my > comments reflect that. > > > Work mode: > > 1.send udp packets > > odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a -c > 192.168.0.1 -d 192.168.0.2 -m u > > 2.receive udp packets > > odp_generator -I eth1 -r > > 3.work likes ping > > odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a -c > 192.168.0.1 -d 192.168.0.2 -m p > > > > The short names here (a,b,c,d) don't match their purpose very well, it's > probably better to stick with the long names. > > > Signed-off-by: Weilong Chen <weilong.chen@linaro.org> > > --- > > .gitignore | 1 + > > test/Makefile | 3 + > > test/generator/Makefile | 46 +++ > > test/generator/odp_generator.c | 847 > ++++++++++++++++++++++++++++++++++++++++ > > 4 files changed, 897 insertions(+) > > create mode 100644 test/generator/Makefile > > create mode 100644 test/generator/odp_generator.c > > > > diff --git a/.gitignore b/.gitignore > > index 53454a5..91055bd 100644 > > --- a/.gitignore > > +++ b/.gitignore > > @@ -14,3 +14,4 @@ test/packet_netmap/odp_packet > > test/api_test/odp_atomic > > test/api_test/odp_shm > > test/api_test/odp_ring > > +test/generator/odp_generator > > diff --git a/test/Makefile b/test/Makefile > > index 2ff7a4c..771b3f4 100644 > > --- a/test/Makefile > > +++ b/test/Makefile > > @@ -9,6 +9,7 @@ all: > > $(MAKE) -C example > > $(MAKE) -C packet > > $(MAKE) -C packet_netmap > > + $(MAKE) -C generator > > > > .PHONY: clean > > clean: > > @@ -16,6 +17,7 @@ clean: > > $(MAKE) -C example clean > > $(MAKE) -C packet clean > > $(MAKE) -C packet_netmap clean > > + $(MAKE) -C generator clean > > > > .PHONY: install > > install: > > @@ -23,3 +25,4 @@ install: > > $(MAKE) -C example install > > $(MAKE) -C packet install > > $(MAKE) -C packet_netmap install > > + $(MAKE) -C generator install > > diff --git a/test/generator/Makefile b/test/generator/Makefile > > new file mode 100644 > > index 0000000..350d2e4 > > --- /dev/null > > +++ b/test/generator/Makefile > > @@ -0,0 +1,46 @@ > > +# Copyright (c) 2013, Linaro Limited > > 2014 > > > +# 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..0ec855b > > --- /dev/null > > +++ b/test/generator/odp_generator.c > > @@ -0,0 +1,847 @@ > > +/* Copyright (c) 2013, Linaro Limited > > 2014 > > > + * All rights reserved. > > + * > > + * SPDX-License-Identifier: BSD-3-Clause > > + */ > > + > > +/** > > + * @file > > + * > > + * @example odp_generator.c ODP loopback demo application > > + */ > > This deserves more of a comment. What does the application do and > how/why do I use it?.. Can the same instance generate and receive packets > or do I need to run multiple instances? Can I run it on multiple cores? > Can it send/receive on multiple interfaces? What sort of performance can > I expect? (I know this is heavily implementation dependant, but is this > intended to achieve close to maximum potential or is it just a gentle > ping?).. etc. > > > + > > +#include <stdlib.h> > > +#include <string.h> > > +#include <getopt.h> > > +#include <unistd.h> > > +#include <stdio.h> > > +#include<sys/time.h> > > + > > +#include <odp.h> > > +#include <helper/odp_packet_helper.h> > > +#include <helper/odp_linux.h> > > +#include <helper/odp_eth.h> > > +#include <helper/odp_ip.h> > > +#include <helper/odp_udp.h> > > +#include <odp_packet_io.h> > > + > > + > > +#define SHM_PKT_POOL_SIZE (512*2048) > > +#define SHM_PKT_POOL_BUF_SIZE 1856 > > + > > + > > +#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)) > > This appears in every application now, it should go in a helper. > > > +/** > > + * Parsed command line application arguments > > + */ > > +typedef struct { > > + 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 */ > > +} appl_args_t; > > + > > +/** > > + * Thread specific arguments > > + */ > > +typedef struct { > > + char *pktio_dev; /**< Interface name to use */ > > + odp_buffer_pool_t pool; /**< Buffer pool for packet IO */ > > + int mode; /**< 0 send, 1 receive */ > > +} thread_args_t; > > + > > +/** > > + * Grouping of both parsed CL args and thread specific args - alloc > together > > + */ > > +#define MAX_WORKERS 1 > > +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 */ > > +void tv_sub(struct timeval *recvtime,struct timeval *sendtime); > > +static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len); > > +static void print_pkts(odp_packet_t pkt_tbl[], unsigned len); > > +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); > > +unsigned int scan_ip(char *ip); > > +int scan_mac(char *in,char *des); > > +void compute_ip_checksum(odp_ipv4hdr_t *iphdrp); > > +void compute_udp_checksum(odp_ipv4hdr_t *pIph, unsigned short > *ipPayload); > > + > > +/* args */ > > +char srcip[20]; > > +char dstip[20]; > > +char srcmac[20]; > > +char dstmac[20]; > > +int pksize = 0; > > +int interval = 1 * 1000; > > +int number = -1; //packets to send > > +int timeout = -1; //timeout seconds > > +int mode; //0 udp, 1 icmp, 2 r; > > Should be an enum and have a more descriptive name, and all of these > args should go into appl_args_t. > > > +int ipcount; > > +int udpcount; > > +int icmpcount; > > +unsigned long long total; > > Similarly could do with a counters structure. I note that there's no > provision here to cope with updating counters from multiple threads, but > given that this implementation is currently limited to a single thread > (per receiver/transmitter) I guess that's out of scope for now. > > > +struct icmphdr { > > + u_int8_t type; /* message type */ > > + u_int8_t code; /* type sub-code */ > > + u_int16_t checksum; > > + u_int16_t id; > > + u_int16_t sequence; > > +}; > > Put this in an odp_icmp.h helper as per odp_udp.h and use uint16be_t. > Also use chksum rather than checksum, to match the others. > > > + > > +/* parser ip */ > > +unsigned int scan_ip(char *ip) > > +{ > > + int part1,part2,part3,part4; > > + unsigned int ipi; > > + > > + sscanf(ip,"%d.%d.%d.%d",&part1,&part2,&part3,&part4); > > + ipi = 0; > > + ipi = part1 <<24 | part2 << 16| part3 << 8 | part4 ; > > + return ipi; > > +} > > + > > +/* parser mac */ > > +int scan_mac(char *in,char *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[i] = mac[i]; > > + } > > + > > + return field; > > +} > > int scan_mac(char *in, uint8_t *mac) > { > return sscanf(in, "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", > &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); > } > > And use odp_ethaddr_t.addr > > > + > > +static unsigned short pcount; > > + > > +/* Compute checksum for count bytes starting at addr, using one's > complement of one's complement sum*/ > > +static unsigned short compute_checksum(unsigned short *addr, unsigned > int count) > > +{ > > + register unsigned long sum = 0; > > + while (count > 1) { > > + sum += * addr++; > > + count -= 2; > > + } > > + //if any bytes left, pad the bytes and add > > + if(count > 0) { > > + sum += ((*addr)&odp_cpu_to_be_16(0xFF00)); > > + } > > + //Fold sum to 16 bits: add carrier to result > > + while (sum>>16) { > > + sum = (sum & 0xffff) + (sum >> 16); > > + } > > + //one's complement > > + sum = ~sum; > > + return ((unsigned short)sum); > > +} > > + > > +/* set ip checksum of a given ip header*/ > > +void compute_ip_checksum(odp_ipv4hdr_t *iphdrp) > > +{ > > + iphdrp->chksum = 0; > > + iphdrp->chksum = compute_checksum((unsigned short*)iphdrp, > iphdrp->ver_ihl<<2); > > +} > > +void compute_udp_checksum(odp_ipv4hdr_t *pIph, unsigned short > *ipPayload) > > +{ > > + register unsigned long sum = 0; > > + odp_udphdr_t *udphdrp = (odp_udphdr_t *)(ipPayload); > > + unsigned short udpLen = odp_cpu_to_be_16(udphdrp->length); > > + //the source ip > > + sum += (pIph->src_addr>>16)&0xFFFF; > > + sum += (pIph->src_addr)&0xFFFF; > > + //the dest ip > > + sum += (pIph->dst_addr>>16)&0xFFFF; > > + sum += (pIph->dst_addr)&0xFFFF; > > + sum += odp_cpu_to_be_16(ODP_IPPROTO_UDP); > > + //the length > > + sum += udphdrp->length; > > + > > + //initialize checksum to 0 > > + udphdrp->chksum = 0; > > + while (udpLen > 1) { > > + sum += * ipPayload++; > > + udpLen -= 2; > > + } > > + //if any bytes left, pad the bytes and add > > + if(udpLen > 0) { > > + sum += ((*ipPayload)&odp_cpu_to_be_16(0xFF00)); > > + } > > + //Fold sum to 16 bits: add carrier to result > > + //printf("add carrier\n"); > > + while (sum>>16) { > > + sum = (sum & 0xffff) + (sum >> 16); > > + } > > + //printf("one's complement\n"); > > + sum = ~sum; > > + //set computation result > > + udphdrp->chksum = ((unsigned short)sum == > 0x0000)?0xFFFF:(unsigned short)sum; > > +} > > The checksum calculations should use odp_chksum(). > > > + > > +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; > > + > > + buf = odp_buffer_addr(obuf); > > + if(buf == NULL) > > + return; > > + max = odp_buffer_size(obuf); > > + if(max <= 0) > > + return; > > + > > + memset(buf, 0, max); > > memset'ing the entire buffer isn't needed. > > > + pkt = odp_packet_from_buffer(obuf); > > + //ether > > + odp_packet_set_l2_offset(pkt, 0); > > + eth = (odp_ethhdr_t *)buf; > > + scan_mac(dstmac,(char *)eth->dst.addr); > > + scan_mac(srcmac,(char *)eth->src.addr); > > This is using sscanf to convert from the strings provided on the > command line for every packet!?.. do it once and store the value. > > > + eth->type = odp_cpu_to_be_16 (ODP_ETHTYPE_IPV4); > > + //ip > > + odp_packet_set_l3_offset(pkt, 14); > > + ip = (odp_ipv4hdr_t *)(buf + 14); > > Use ODP_ETHHDR_LEN. There are lots of other magic numbers used in this > patch that should be changed too. > > > + ip->dst_addr = odp_cpu_to_be_32(scan_ip(dstip)); > > + ip->src_addr = odp_cpu_to_be_32(scan_ip(srcip)); > > Same comment as above, don't use scan_ip here. > > > + ip->ver_ihl = ODP_IPV4<<4|5; > > + ip->tot_len = odp_cpu_to_be_16(pksize + 8 + 20); > > + ip->proto = ODP_IPPROTO_UDP; > > + ip->id = odp_cpu_to_be_16(pcount++); > > + compute_ip_checksum(ip); > > + //udp > > + udp = (odp_udphdr_t *) (buf + 14 + 20); > > + udp->src_port = 0; > > + udp->dst_port = 0; > > + udp->length = odp_cpu_to_be_16(pksize + 8); > > + udp->chksum = 0; > > + compute_udp_checksum(ip, (unsigned short *)udp); > > + > > + odp_packet_set_len(pkt,pksize + 8 + 20 + 14); > > +} > > + > > +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; > > + struct icmphdr *icmp; > > + struct timeval *tval; > > + > > + buf = odp_buffer_addr(obuf); > > + if(buf == NULL) > > + return; > > + max = odp_buffer_size(obuf); > > + if(max <= 0) > > + return; > > + > > + memset(buf, 0, max); > > don't memset the entire buffer > > > + pksize = 56; //set icmp size 56 > > + pkt = odp_packet_from_buffer(obuf); > > + //ether > > + odp_packet_set_l2_offset(pkt, 0); > > + eth = (odp_ethhdr_t *)buf; > > + scan_mac(dstmac,(char *)eth->dst.addr); > > + scan_mac(srcmac,(char *)eth->src.addr); > > don't use scan_mac here > > > + eth->type = odp_cpu_to_be_16 (ODP_ETHTYPE_IPV4); > > + //ip > > + odp_packet_set_l3_offset(pkt, 14); > > + ip = (odp_ipv4hdr_t *)(buf + 14); > > + ip->dst_addr = odp_cpu_to_be_32(scan_ip(dstip)); > > + ip->src_addr = odp_cpu_to_be_32(scan_ip(srcip)); > > don't use scan_ip here > > > + ip->ver_ihl = ODP_IPV4<<4|5; > > + ip->tot_len = odp_cpu_to_be_16(56 + 8 + 20); > > + ip->proto = ODP_IPPROTO_ICMP; > > + ip->id = odp_cpu_to_be_16(pcount++); > > + compute_ip_checksum(ip); > > + //icmp > > + icmp = (struct icmphdr *) (buf + 14 + 20); > > + icmp->type = 8; //Echo Request > > + icmp->code = 0; > > + icmp->id = odp_cpu_to_be_16(pcount - 1); > > + icmp->sequence = odp_cpu_to_be_16(pcount - 1); > > + tval = (struct timeval *)(buf + 14 + 20 + 8); > > + gettimeofday(tval,NULL); > > gettimeofday causes a syscall. This should be changed to use an ODP > timer API once one exists. > > > + icmp->checksum = 0; > > + icmp->checksum = compute_checksum((unsigned short *)icmp, 64); > > + > > + odp_packet_set_len(pkt,56 + 8 + 20 + 14); > > +} > > + > > + > > + > > +/** > > + * Packet IO loopback worker thread using ODP queues > > + * > > + * @param arg thread arguments of type 'thread_args_t *' > > + */ > > +static void *pktio_queue_thread(void *arg) > > +{ > > + int thr; > > + odp_buffer_pool_t pkt_pool; > > + odp_pktio_t pktio; > > + thread_args_t *thr_args; > > + odp_queue_t outq_def; > > + 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; > > + > > + if(mode == 1&& thr_args->mode != 2) > > + sleep(1); //wait receiver ok; > > Don't sleep, use a barrier. > > > + printf("Pktio thread [%02i] starts, pktio_dev:%s\n", thr, > > + thr_args->pktio_dev); > > + > > + /* Lookup the packet pool */ > > + pkt_pool = odp_buffer_pool_lookup("packet_pool"); > > + if (pkt_pool == ODP_BUFFER_POOL_INVALID) { > > + ODP_ERR(" [%02i] Error: pkt_pool not found\n", thr); > > + return NULL; > > + } > > + > > + /* Open a packet IO instance for this thread */ > > + sock_params->type = ODP_PKTIO_TYPE_SOCKET; > > + 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; > > + } > > + > > + if (thr_args->mode == 0 || thr_args->mode == 1) { > > Different modes of operation should be factored out into separate > functions for clarity, perhaps it would be clearer to use a different > thr_run_func for receiver and transmitter. > > Again the use of magic numbers and the mix of application mode vs thread > mode doesn't help understand what's going on. > > > + 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; > > + } > > + > > + for(;;) { > > + int err; > > + buf = odp_buffer_alloc(pkt_pool); > > + if (!odp_buffer_is_valid(buf)) { > > + ODP_ERR(" [%i] alloc_single failed\n", > thr); > > + return NULL; > > So this thread dies.. what happens to the other(s)? > > > + } > > + > > + if(thr_args->mode == 0) > > + pack_udp_pkt(buf); > > + else > > + pack_icmp_pkt(buf); > > + > > + err = odp_queue_enq(outq_def, buf); > > + total++; > > + if (err != 0) { > > + printf("send pkt err!\n"); > > Use ODP_ERR > > > + return NULL; > > + } > > + if(interval != 0) { //flood mode will not print > msg > > But the else has exactly the same printf.. > > > + printf("Generator send pkt no:%llu seq > %d size:%d\n", total,pcount - 1, pksize); > > + usleep(interval * 1000); > > Again, shouldn't be sleeping here, you should instead kick off a timer > to generate an event when the next packet needs to be sent. I'm not sure > of the status of the current timer API so it might not be possible to > make this change yet. > > > + } else { > > + printf("Generator send pkt no:%llu seq > %d size:%d\r", total,pcount - 1, pksize); > > + } > > + if (number != -1 && (int)total >= number) { > > + break; > > + } > > You have an unsigned long long counter which is only used for checking > that it's within the range on a signed int, that doesn't make a lot of > sense. > > > + > > + } > > + //if timeout >= 0; > > + while(mode == 1 && timeout >= 0) { > > + if(icmpcount >= number) > > + break; > > + sleep(1); > > + timeout--; > > + } > > I'm confused as to what this block is achieving. It certainly doesn't > seem to be using timeout in the way that is suggested in the help text. > It looks like the intended purpose isn't supported at all. > > > + //print info: > > + if(mode == 0) { > > + printf("Total send:%llu\n",total); > > + } else if (mode == 1) { > > + printf("Total send:%llu,total receiver > %d\n",total,icmpcount); > > + } > > + exit(0); > > Remove this exit, just allow the function to return. > > > + > > + } else if(thr_args->mode == 2) { > > + 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; > > + } > > + > > + for (;;) { > > + /* Use schedule to get buf from any input queue > */ > > + buf = odp_schedule(NULL); > > + > > + pkt = odp_packet_from_buffer(buf); > > + /* Drop packets with errors */ > > + if (odp_unlikely(drop_err_pkts(&pkt, 1) == 0)) { > > + ODP_ERR("Drop frame\n"); > > + continue; > > + } > > + > > + /* Swap Eth MACs and possibly IP-addrs before > sending back */ > > + print_pkts(&pkt, 1); > > Comment is wrong. > > > + > > + odp_packet_free(pkt); > > + > > + } > > + > > + } > > + > > + return arg; > > +} > > + > > +/** > > + * Swap eth src<->dst and IP src<->dst addresses > > Comment is wrong. > > > + * > > + * @param pkt_tbl Array of packets > > + * @param len Length of pkt_tbl[] > > + */ > > + > > +static void print_pkts(odp_packet_t pkt_tbl[], unsigned len) > > +{ > > + odp_packet_t pkt; > > + char *buf; > > + odp_ipv4hdr_t *ip; > > + odp_udphdr_t *udp; > > + struct icmphdr *icmp; > > + struct timeval tvrecv; > > + struct timeval *tvsend; > > + double rtt; > > + unsigned i; > > + char msg[1024]; > > + int rlen = 0; > > rlen should be reset inside the loop to avoid an overflow when len>1 > (though actually the caller has hard coded len to 1 so it can't happen > as it is). > > > + FILE *stream; > > + for (i = 0; i < len; ++i) { > > + pkt = pkt_tbl[i]; > > + memset(msg, 0, 1024); > > don't need to memset the entire msg, if you're being cautious the most > you need is: msg[0] = '\0'; > > > + // print ip header > > + if(odp_packet_inflag_ipv4(pkt)) { > > + ipcount++; > > + 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)); > > + //ip = (odp_ipv4hdr_t *)odp_packet_l3(pkt); > > + rlen += sprintf(msg + rlen,"id %d > ",odp_be_to_cpu_16(ip->id)); > > + > > + //udp > > + if(ip->proto == ODP_IPPROTO_UDP) { > > + udpcount++; > > + udp = (odp_udphdr_t *)(buf + > odp_packet_l4_offset(pkt)); > > + rlen += sprintf(msg + rlen," UDP payload > %d ",odp_be_to_cpu_16(udp->length) - 8); > > + } > > + > > + //icmp > > + if(ip->proto == ODP_IPPROTO_ICMP) { > > + icmp = (struct icmphdr *)(buf + > odp_packet_l4_offset(pkt)); > > + if(icmp->type == 0) { > > + icmpcount++; > > + tvsend = (struct timeval *)(buf > + odp_packet_l4_offset(pkt) + 8); > > + gettimeofday(&tvrecv,NULL); > > Same comment as previous re gettimeofday > > > + tv_sub(&tvrecv,tvsend); > > + rtt = tvrecv.tv_sec*1000 + > tvrecv.tv_usec/1000; > > + rlen += sprintf(msg + rlen, > "ICMP seq %d time %.1f ",odp_be_to_cpu_16(icmp->sequence), rtt); > > + if(mode == 1) //ping mode > > + printf("%s\n",msg); > > + } > > + > > + } > > + if (mode == 2) //receiver mode > > + printf("%s\n",msg); > > I don't really like the way msg is constructed, looks like it could be > constructed and then not used. Splitting out the ICMP and UDP stuff > would simplify things. > > > + stream = fopen( "/tmp/recv.log", "a" ); > > + fprintf(stream, "Receive pkt > NO:%d\n",odp_be_to_cpu_16(ip->id)); > > + fclose( stream ); > > Hrm.. I think we need to sort out a logging framework as this sort of > thing really shouldn't be here. > > > + } > > + > > + } > > +} > > + > > +/** > > + * 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; > > + > > + /* Init ODP before calling anything else */ > > + if (odp_init_global()) { > > + ODP_ERR("Error: ODP global init failed.\n"); > > + exit(EXIT_FAILURE); > > + } > > + > > + /* 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); > > + > > + /* 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 (mode == 1) > > + num_workers = 2; > > + else > > + num_workers = 1; > > + > > This num_workers pegging is a bit restrictive. It would obviously be > good to be able to use more cores (would need rework of the globals) > > > + if (mode == 0) { > > + printf("Work mode: send udp packets\n\n"); > > + } else if (mode == 1) { > > + printf("Work mode: ping\n\n"); > > + } else if (mode == 2) { > > + printf("Work mode: receive ip packets\n\n"); > > + } else { > > + printf("Wrong mode\n"); > > + exit(EXIT_FAILURE); > > + } > > + for (i = 0; i < num_workers; ++i) { > > + void *(*thr_run_func) (void *); > > + int 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 = mode; > > + if(i == 1) > > + args->thread[i].mode = 2; > > + thr_run_func = pktio_queue_thread; > > + /* > > + * 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, i, 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 > > + */ > > +#pragma GCC diagnostic push // require GCC 4.6 > > +#pragma GCC diagnostic ignored "-Wcast-qual" > > +#pragma GCC diagnostic ignored "-Werror" > > Why is this needed? > > > +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'}, /* > return 'i' */ > > + {"srcmac", required_argument, NULL, 'a'}, > /* return 'm' */ > > + {"dstmac", required_argument, NULL, 'b'}, > /* return 'm' */ > > + {"srcip", required_argument, NULL, 'c'}, > /* return 'm' */ > > + {"dstip", required_argument, NULL, 'd'}, > /* return 'm' */ > > + {"packetsize", required_argument, NULL, 's'}, > /* return 'h' */ > > + {"mode", required_argument, NULL, 'm'}, > > + {"count", required_argument, NULL, 'n'}, > > + {"timeout", required_argument, NULL, 't'}, > > + {"interval", required_argument, NULL, 'i'}, > /* return 'h' */ > > + {"help", no_argument, NULL, 'h'}, /* > return 'h' */ > > + {NULL, 0, NULL, 0} > > + }; > > The "return '?'" comments are not correct and seem a bit pointless. > > > + > > + > > + while (1) { > > + opt = getopt_long(argc, argv, "+I:a:b:c:d:s:i:m:n:t:h", > longopts, &long_index); > > + > > + if (opt == -1) > > + break; /* No more options */ > > + > > + switch (opt) { > > + /* 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; > > There's an identical chunk in odp_example_pktio[_netmap].c so this > should be put in a helper. > > > + case 'a': > > + strcpy(srcmac, optarg); > > + break; > > + case 'b': > > + strcpy(dstmac, optarg); > > + break; > > + > > + case 'c': > > + strcpy(srcip, optarg); > > + break; > > + > > + case 'd': > > + strcpy(dstip, optarg); > > + break; > > + case 's': > > + pksize = atoi(optarg); > > + if(pksize > SHM_PKT_POOL_BUF_SIZE - 14 - 20 - 8) > { > > There are #defines for ODP_ETHHDR_LEN and ODP_IPV4HDR_LEN already. > Although I think this check should be moved to a later point because you > don't (necessarily) know what protocol you're using, the 8 here could be > either ICMP header length or UDP header length (ok they are both 8 > bytes, but that's a coincidence). > > > + printf("the pksize is too big!\n"); > > + exit(EXIT_FAILURE); > > + } > > + break; > > + case 'm': > > + if(optarg[0] == 'u') { > > + mode = 0; > > + } else if (optarg[0] == 'p') { > > + mode = 1; > > + } else if (optarg[0] == 'r') { > > + mode = 2; > > named enums needed here. > > > + } else { > > + printf("wrong mode!\n"); > > + exit(EXIT_FAILURE); > > + } > > + break; > > + case 'n': > > + number = atoi(optarg); > > + break; > > + case 't': > > + timeout = atoi(optarg); > > + break; > > + case 'i': > > + interval = atoi(optarg); > > + if(interval <= 200 && geteuid() != 0) { > > + printf("Only super-user may set interval > to values less 0.2 seconds.\n"); > > + exit(EXIT_FAILURE); > > + } > > + break; > > + case 'h': > > + usage(argv[0]); > > + exit(EXIT_SUCCESS); > > + break; > > + > > + default: > > + break; > > + } > > + } > > + > > + > > + optind = 1; /* reset 'extern optind' from the getopt > lib */ > > +} > > +#pragma GCC diagnostic pop > > +/** > > + * 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 freq (hz): %"PRIu64"\n" > > + "Cache line size: %i\n" > > + "Core count: %i\n" > > + "\n", > > + odp_version_api_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\n"); > > + fflush(NULL); > > +} > > print_info should go into a helper. > > > + > > +/** > > + * 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 veth0 -a fe:0f:97:c9:e0:44 -b > 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m u\n" > > + " 2.receive udp packets\n" > > + " 3.work likes ping\n" > > + " odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b > 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m p\n" > > + "\n" > > + "Mandatory OPTIONS:\n" > > + " -I, --interface Eth interfaces (comma-separated, no > spaces)\n" > > + " -a, --srcmac src mac adddress\n" > > + " -b, --dstmac dst mac adddress\n" > > + " -c, --srcip src ip adddress\n" > > + " -d, --dstip dst ip adddress\n" > > s/adddress/address/ > > > + " -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 floord mode\n" > > s/floord/flood/ > > > + "\n" > > + "Optional OPTIONS\n" > > + " -h, --help Display help and exit.\n" > > + "\n", NO_PATH(progname), NO_PATH(progname) > > + ); > > +} > > +/** > > + * Drop packets which input parsing marked as containing errors. > > + * > > + * Frees packets with error and modifies pkt_tbl[] to only contain > packets with > > + * no detected errors. > > + * > > + * @param pkt_tbl Array of packet > > + * @param len Length of pkt_tbl[] > > + * > > + * @return Number of packets with no detected error > > + */ > > +static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len) > > +{ > > + odp_packet_t pkt; > > + unsigned pkt_cnt = len; > > + unsigned i, j; > > + > > + for (i = 0, j = 0; i < len; ++i) { > > + pkt = pkt_tbl[i]; > > + > > + if (odp_unlikely(odp_packet_error(pkt))) { > > + odp_packet_free(pkt); /* Drop */ > > + pkt_cnt--; > > + } else if (odp_unlikely(i != j++)) { > > + pkt_tbl[j] = pkt; > > + } > > + } > > + > > + return pkt_cnt; > > +} > > + > > The above function is a duplicate of the one in odp_example_pktio.c, it > should be moved to a helper file. > > > +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; > > + } > > +} > > -- > Stuart. > > -- > You received this message because you are subscribed to the Google Groups > "LNG ODP Sub-team - lng-odp@linaro.org" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to lng-odp+unsubscribe@linaro.org. > To post to this group, send email to lng-odp@linaro.org. > Visit this group at http://groups.google.com/a/linaro.org/group/lng-odp/. > To view this discussion on the web visit > https://groups.google.com/a/linaro.org/d/msgid/lng-odp/20140321144753.GA11424%40e106441 > . > For more options, visit https://groups.google.com/a/linaro.org/d/optout. >
On 03/21/2014 06:47 PM, Stuart Haslam wrote: > Work mode: > > 1.send udp packets > > odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m u > > 2.receive udp packets > > odp_generator -I eth1 -r > > 3.work likes ping > > odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m p Why we are not porting tcpreplay or blasting/saving pcap files? Send predefined packets from file might be more useful then generated one. At least for debugging flow splitting. Do you want to add also pcap functionality there? I think you can copy paste send / recieve function from my old example: https://git.linaro.org/people/maxim.uvarov/odp.git/commit/b1e5d819090e57509cdc1c42f185ce2e85f6bd29 Thanks, Maxim.
tcpreplay is available, and Weilong is trying to get it added to qa/testing, Anders keeps nacking it ;) do we need an ODP version that just plays into a queue ? - if so we can add a CARD. On 21 March 2014 11:13, Maxim Uvarov <maxim.uvarov@linaro.org> wrote: > On 03/21/2014 06:47 PM, Stuart Haslam wrote: > >> Work mode: >> > 1.send udp packets >> > odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a >> -c 192.168.0.1 -d 192.168.0.2 -m u >> > 2.receive udp packets >> > odp_generator -I eth1 -r >> > 3.work likes ping >> > odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a >> -c 192.168.0.1 -d 192.168.0.2 -m p >> > > Why we are not porting tcpreplay or blasting/saving pcap files? Send > predefined packets from file might be more useful then generated one. > At least for debugging flow splitting. > > Do you want to add also pcap functionality there? I think you can copy > paste send / recieve function from my old example: > https://git.linaro.org/people/maxim.uvarov/odp.git/commit/ > b1e5d819090e57509cdc1c42f185ce2e85f6bd29 > > Thanks, > Maxim. > > > -- > You received this message because you are subscribed to the Google Groups > "LNG ODP Sub-team - lng-odp@linaro.org" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to lng-odp+unsubscribe@linaro.org. > To post to this group, send email to lng-odp@linaro.org. > Visit this group at http://groups.google.com/a/linaro.org/group/lng-odp/. > To view this discussion on the web visit https://groups.google.com/a/ > linaro.org/d/msgid/lng-odp/532C56FC.2010701%40linaro.org. > > For more options, visit https://groups.google.com/a/linaro.org/d/optout. >
On 03/21/2014 07:16 PM, Mike Holmes wrote: > tcpreplay is available, and Weilong is trying to get it added to > qa/testing, Anders keeps nacking it ;) do we need an ODP version that > just plays into a queue ? - if so we can add a CARD. yes, we need to write requirements somewhere. Probably wiki page is good for that. At least what I would like to expect. Odp-tcpreplay: 1. uses odp for packet processing (accelerated I/O). 2. able to select number of used cpus. 3. able to support all functionality for standard tcpreplay (delays, traffic speed and etc.). 4. (not sure if tcpreplay can save to files) able to save to files per-cpu/queques pcaps. Maxim. > > > On 21 March 2014 11:13, Maxim Uvarov <maxim.uvarov@linaro.org > <mailto:maxim.uvarov@linaro.org>> wrote: > > On 03/21/2014 06:47 PM, Stuart Haslam wrote: > > Work mode: > > 1.send udp packets > > odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b > 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m u > > 2.receive udp packets > > odp_generator -I eth1 -r > > 3.work likes ping > > odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b > 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m p > > > Why we are not porting tcpreplay or blasting/saving pcap files? > Send predefined packets from file might be more useful then > generated one. > At least for debugging flow splitting. > > Do you want to add also pcap functionality there? I think you can > copy paste send / recieve function from my old example: > https://git.linaro.org/people/maxim.uvarov/odp.git/commit/b1e5d819090e57509cdc1c42f185ce2e85f6bd29 > > Thanks, > Maxim. > > > -- > You received this message because you are subscribed to the Google > Groups "LNG ODP Sub-team - lng-odp@linaro.org > <mailto:lng-odp@linaro.org>" group. > To unsubscribe from this group and stop receiving emails from it, > send an email to lng-odp+unsubscribe@linaro.org > <mailto:lng-odp%2Bunsubscribe@linaro.org>. > To post to this group, send email to lng-odp@linaro.org > <mailto:lng-odp@linaro.org>. > Visit this group at > http://groups.google.com/a/linaro.org/group/lng-odp/. > To view this discussion on the web visit > https://groups.google.com/a/linaro.org/d/msgid/lng-odp/532C56FC.2010701%40linaro.org. > > > For more options, visit > https://groups.google.com/a/linaro.org/d/optout. > >
Thanks Maxim. I will capture these items in a CARD to investigate an ODP specific tcpreplay. On 21 March 2014 11:26, Maxim Uvarov <maxim.uvarov@linaro.org> wrote: > On 03/21/2014 07:16 PM, Mike Holmes wrote: > >> tcpreplay is available, and Weilong is trying to get it added to >> qa/testing, Anders keeps nacking it ;) do we need an ODP version that just >> plays into a queue ? - if so we can add a CARD. >> > > yes, we need to write requirements somewhere. Probably wiki page is good > for that. > At least what I would like to expect. > > Odp-tcpreplay: > > 1. uses odp for packet processing (accelerated I/O). > 2. able to select number of used cpus. > 3. able to support all functionality for standard tcpreplay (delays, > traffic speed and etc.). > 4. (not sure if tcpreplay can save to files) able to save to files > per-cpu/queques pcaps. > > Maxim. > >> >> >> On 21 March 2014 11:13, Maxim Uvarov <maxim.uvarov@linaro.org <mailto: >> maxim.uvarov@linaro.org>> wrote: >> >> On 03/21/2014 06:47 PM, Stuart Haslam wrote: >> >> Work mode: >> > 1.send udp packets >> > odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b >> 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m u >> > 2.receive udp packets >> > odp_generator -I eth1 -r >> > 3.work likes ping >> > odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b >> 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m p >> >> >> Why we are not porting tcpreplay or blasting/saving pcap files? >> Send predefined packets from file might be more useful then >> generated one. >> At least for debugging flow splitting. >> >> Do you want to add also pcap functionality there? I think you can >> copy paste send / recieve function from my old example: >> https://git.linaro.org/people/maxim.uvarov/odp.git/commit/ >> b1e5d819090e57509cdc1c42f185ce2e85f6bd29 >> >> Thanks, >> Maxim. >> >> >> -- You received this message because you are subscribed to the >> Google >> Groups "LNG ODP Sub-team - lng-odp@linaro.org >> <mailto:lng-odp@linaro.org>" group. >> >> To unsubscribe from this group and stop receiving emails from it, >> send an email to lng-odp+unsubscribe@linaro.org >> <mailto:lng-odp%2Bunsubscribe@linaro.org>. >> >> To post to this group, send email to lng-odp@linaro.org >> <mailto:lng-odp@linaro.org>. >> >> Visit this group at >> http://groups.google.com/a/linaro.org/group/lng-odp/. >> To view this discussion on the web visit >> https://groups.google.com/a/linaro.org/d/msgid/lng-odp/ >> 532C56FC.2010701%40linaro.org. >> >> >> For more options, visit >> https://groups.google.com/a/linaro.org/d/optout. >> >> >> > -- > You received this message because you are subscribed to the Google Groups > "LNG ODP Sub-team - lng-odp@linaro.org" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to lng-odp+unsubscribe@linaro.org. > To post to this group, send email to lng-odp@linaro.org. > Visit this group at http://groups.google.com/a/linaro.org/group/lng-odp/. > To view this discussion on the web visit https://groups.google.com/a/ > linaro.org/d/msgid/lng-odp/532C5A27.6080705%40linaro.org. > > For more options, visit https://groups.google.com/a/linaro.org/d/optout. >
On Fri, Mar 21, 2014 at 03:09:17PM +0000, Mike Holmes wrote: > Stuart, there are already a number of cards to increase this tools > utility, and feature requests are eagerly sought, but this is just the > first evolution beyond the demo ping app. > > I think it should form a significant role in our testing when > complete. > OK, sounds good. By the way, there's a pktgen tool for DPDK here; https://github.com/Pktgen/Pktgen-DPDK Some of my comments were about missing functionality, either in this app or in ODP in general, and fixes for those can/should be deferred (but most were related to things that should be fixed even for the first revision).
On Fri, Mar 21, 2014 at 03:09:17PM +0000, Mike Holmes wrote: > Stuart, there are already a number of cards to increase this tools > utility, and feature requests are eagerly sought, but this is just the > first evolution beyond the demo ping app. > > I think it should form a significant role in our testing when > complete. > [my mailer seems to have mangled the previous message.. trying again :] OK, sounds good. By the way, there's a pktgen tool for DPDK here; https://github.com/Pktgen/Pktgen-DPDK Some of my comments were about missing functionality, either in this app or in ODP in general, and fixes for those can/should be deferred (but most were related to things that should be fixed even for the first revision).
Thanks! On 22 March 2014 01:13, Stuart Haslam <stuart.haslam@arm.com> wrote: > On Fri, Mar 21, 2014 at 03:09:17PM +0000, Mike Holmes wrote: > > Stuart, there are already a number of cards to increase this tools > > utility, and feature requests are eagerly sought, but this is just the > > first evolution beyond the demo ping app. > > > > I think it should form a significant role in our testing when > > complete. > > > > [my mailer seems to have mangled the previous message.. trying again :] > > OK, sounds good. By the way, there's a pktgen tool for DPDK here; > https://github.com/Pktgen/Pktgen-DPDK > > Some of my comments were about missing functionality, either in this app > or in ODP in general, and fixes for those can/should be deferred (but > most were related to things that should be fixed even for the first > revision). > > -- > Stuart. > >
I have a couple of packet generation tools that I could contribute (yes it is allowed now! just three months of waiting). My tools are more geared towards generating flows (as defined by IP five-tuples) with different characteristics (number of flows, number of packets, fragmentation thresholds). Currently pcap files are generated, perhaps it should also be possible to transmit the packets (on some interface) as they are generated. If we would have a demo application implementing e.g. NAT, we would need to generate suitable packet traces and not just ping/UDP-echo-type traffic. On 24 March 2014 10:23, Weilong Chen <weilong.chen@linaro.org> wrote: > Thanks! > > > On 22 March 2014 01:13, Stuart Haslam <stuart.haslam@arm.com> wrote: > >> On Fri, Mar 21, 2014 at 03:09:17PM +0000, Mike Holmes wrote: >> > Stuart, there are already a number of cards to increase this tools >> > utility, and feature requests are eagerly sought, but this is just the >> > first evolution beyond the demo ping app. >> > >> > I think it should form a significant role in our testing when >> > complete. >> > >> >> [my mailer seems to have mangled the previous message.. trying again :] >> >> OK, sounds good. By the way, there's a pktgen tool for DPDK here; >> https://github.com/Pktgen/Pktgen-DPDK >> >> Some of my comments were about missing functionality, either in this app >> or in ODP in general, and fixes for those can/should be deferred (but >> most were related to things that should be fixed even for the first >> revision). >> >> -- >> Stuart. >> >> > -- > You received this message because you are subscribed to the Google Groups > "LNG ODP Sub-team - lng-odp@linaro.org" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to lng-odp+unsubscribe@linaro.org. > To post to this group, send email to lng-odp@linaro.org. > Visit this group at http://groups.google.com/a/linaro.org/group/lng-odp/. > To view this discussion on the web visit > https://groups.google.com/a/linaro.org/d/msgid/lng-odp/CAD0aSzk%2BM05Ua_vr%3D_cGyCmscbxbU-Tq4aNetBXgtG2gk8S5SQ%40mail.gmail.com<https://groups.google.com/a/linaro.org/d/msgid/lng-odp/CAD0aSzk%2BM05Ua_vr%3D_cGyCmscbxbU-Tq4aNetBXgtG2gk8S5SQ%40mail.gmail.com?utm_medium=email&utm_source=footer> > . > > For more options, visit https://groups.google.com/a/linaro.org/d/optout. >
Thanks Ola, Will you be able to get them into a format that can be submitted to ODP/test or will they need work by another Engineer? Mike On 24 March 2014 08:10, Ola Liljedahl <ola.liljedahl@linaro.org> wrote: > I have a couple of packet generation tools that I could contribute (yes it > is allowed now! just three months of waiting). > > My tools are more geared towards generating flows (as defined by IP > five-tuples) with different characteristics (number of flows, number of > packets, fragmentation thresholds). Currently pcap files are generated, > perhaps it should also be possible to transmit the packets (on some > interface) as they are generated. If we would have a demo application > implementing e.g. NAT, we would need to generate suitable packet traces and > not just ping/UDP-echo-type traffic. > > > > On 24 March 2014 10:23, Weilong Chen <weilong.chen@linaro.org> wrote: > >> Thanks! >> >> >> On 22 March 2014 01:13, Stuart Haslam <stuart.haslam@arm.com> wrote: >> >>> On Fri, Mar 21, 2014 at 03:09:17PM +0000, Mike Holmes wrote: >>> > Stuart, there are already a number of cards to increase this tools >>> > utility, and feature requests are eagerly sought, but this is just the >>> > first evolution beyond the demo ping app. >>> > >>> > I think it should form a significant role in our testing when >>> > complete. >>> > >>> >>> [my mailer seems to have mangled the previous message.. trying again :] >>> >>> OK, sounds good. By the way, there's a pktgen tool for DPDK here; >>> https://github.com/Pktgen/Pktgen-DPDK >>> >>> Some of my comments were about missing functionality, either in this app >>> or in ODP in general, and fixes for those can/should be deferred (but >>> most were related to things that should be fixed even for the first >>> revision). >>> >>> -- >>> Stuart. >>> >>> >> -- >> You received this message because you are subscribed to the Google Groups >> "LNG ODP Sub-team - lng-odp@linaro.org" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to lng-odp+unsubscribe@linaro.org. >> To post to this group, send email to lng-odp@linaro.org. >> Visit this group at http://groups.google.com/a/linaro.org/group/lng-odp/. >> To view this discussion on the web visit >> https://groups.google.com/a/linaro.org/d/msgid/lng-odp/CAD0aSzk%2BM05Ua_vr%3D_cGyCmscbxbU-Tq4aNetBXgtG2gk8S5SQ%40mail.gmail.com<https://groups.google.com/a/linaro.org/d/msgid/lng-odp/CAD0aSzk%2BM05Ua_vr%3D_cGyCmscbxbU-Tq4aNetBXgtG2gk8S5SQ%40mail.gmail.com?utm_medium=email&utm_source=footer> >> . >> >> For more options, visit https://groups.google.com/a/linaro.org/d/optout. >> > > -- > You received this message because you are subscribed to the Google Groups > "LNG ODP Sub-team - lng-odp@linaro.org" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to lng-odp+unsubscribe@linaro.org. > To post to this group, send email to lng-odp@linaro.org. > Visit this group at http://groups.google.com/a/linaro.org/group/lng-odp/. > To view this discussion on the web visit > https://groups.google.com/a/linaro.org/d/msgid/lng-odp/CAPiYAf6C-pdwX4G_8kEN_auwWGD14M_wmk5HdBnnGoKMjU7tbg%40mail.gmail.com<https://groups.google.com/a/linaro.org/d/msgid/lng-odp/CAPiYAf6C-pdwX4G_8kEN_auwWGD14M_wmk5HdBnnGoKMjU7tbg%40mail.gmail.com?utm_medium=email&utm_source=footer> > . > > For more options, visit https://groups.google.com/a/linaro.org/d/optout. >
What is required in order to comply with this "ODP/test format"? If I try to mimic odp-generator (?), will I be close then? I will likely need help from some other engineer. I do have some other things to work on which I think are more important (to me and ARM). On 24 March 2014 13:14, Mike Holmes <mike.holmes@linaro.org> wrote: > Thanks Ola, > > Will you be able to get them into a format that can be submitted to > ODP/test or will they need work by another Engineer? > > Mike > > > On 24 March 2014 08:10, Ola Liljedahl <ola.liljedahl@linaro.org> wrote: > >> I have a couple of packet generation tools that I could contribute (yes >> it is allowed now! just three months of waiting). >> >> My tools are more geared towards generating flows (as defined by IP >> five-tuples) with different characteristics (number of flows, number of >> packets, fragmentation thresholds). Currently pcap files are generated, >> perhaps it should also be possible to transmit the packets (on some >> interface) as they are generated. If we would have a demo application >> implementing e.g. NAT, we would need to generate suitable packet traces and >> not just ping/UDP-echo-type traffic. >> >> >> >> On 24 March 2014 10:23, Weilong Chen <weilong.chen@linaro.org> wrote: >> >>> Thanks! >>> >>> >>> On 22 March 2014 01:13, Stuart Haslam <stuart.haslam@arm.com> wrote: >>> >>>> On Fri, Mar 21, 2014 at 03:09:17PM +0000, Mike Holmes wrote: >>>> > Stuart, there are already a number of cards to increase this tools >>>> > utility, and feature requests are eagerly sought, but this is just the >>>> > first evolution beyond the demo ping app. >>>> > >>>> > I think it should form a significant role in our testing when >>>> > complete. >>>> > >>>> >>>> [my mailer seems to have mangled the previous message.. trying again :] >>>> >>>> OK, sounds good. By the way, there's a pktgen tool for DPDK here; >>>> https://github.com/Pktgen/Pktgen-DPDK >>>> >>>> Some of my comments were about missing functionality, either in this app >>>> or in ODP in general, and fixes for those can/should be deferred (but >>>> most were related to things that should be fixed even for the first >>>> revision). >>>> >>>> -- >>>> Stuart. >>>> >>>> >>> -- >>> You received this message because you are subscribed to the Google >>> Groups "LNG ODP Sub-team - lng-odp@linaro.org" group. >>> To unsubscribe from this group and stop receiving emails from it, send >>> an email to lng-odp+unsubscribe@linaro.org. >>> To post to this group, send email to lng-odp@linaro.org. >>> Visit this group at http://groups.google.com/a/linaro.org/group/lng-odp/ >>> . >>> To view this discussion on the web visit >>> https://groups.google.com/a/linaro.org/d/msgid/lng-odp/CAD0aSzk%2BM05Ua_vr%3D_cGyCmscbxbU-Tq4aNetBXgtG2gk8S5SQ%40mail.gmail.com<https://groups.google.com/a/linaro.org/d/msgid/lng-odp/CAD0aSzk%2BM05Ua_vr%3D_cGyCmscbxbU-Tq4aNetBXgtG2gk8S5SQ%40mail.gmail.com?utm_medium=email&utm_source=footer> >>> . >>> >>> For more options, visit https://groups.google.com/a/linaro.org/d/optout. >>> >> >> -- >> You received this message because you are subscribed to the Google Groups >> "LNG ODP Sub-team - lng-odp@linaro.org" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to lng-odp+unsubscribe@linaro.org. >> To post to this group, send email to lng-odp@linaro.org. >> Visit this group at http://groups.google.com/a/linaro.org/group/lng-odp/. >> To view this discussion on the web visit >> https://groups.google.com/a/linaro.org/d/msgid/lng-odp/CAPiYAf6C-pdwX4G_8kEN_auwWGD14M_wmk5HdBnnGoKMjU7tbg%40mail.gmail.com<https://groups.google.com/a/linaro.org/d/msgid/lng-odp/CAPiYAf6C-pdwX4G_8kEN_auwWGD14M_wmk5HdBnnGoKMjU7tbg%40mail.gmail.com?utm_medium=email&utm_source=footer> >> . >> >> For more options, visit https://groups.google.com/a/linaro.org/d/optout. >> > >
My packet generators are not utilizing ODP, performance and scalability have not been an issue for me. I wasn't thinking of using them as demo apps for ODP, just for generating suitable traffic for the actual demo. On 24 March 2014 13:30, Ola Liljedahl <ola.liljedahl@linaro.org> wrote: > What is required in order to comply with this "ODP/test format"? > If I try to mimic odp-generator (?), will I be close then? > I will likely need help from some other engineer. I do have some other > things to work on which I think are more important (to me and ARM). > > > On 24 March 2014 13:14, Mike Holmes <mike.holmes@linaro.org> wrote: > >> Thanks Ola, >> >> Will you be able to get them into a format that can be submitted to >> ODP/test or will they need work by another Engineer? >> >> Mike >> >> >> On 24 March 2014 08:10, Ola Liljedahl <ola.liljedahl@linaro.org> wrote: >> >>> I have a couple of packet generation tools that I could contribute (yes >>> it is allowed now! just three months of waiting). >>> >>> My tools are more geared towards generating flows (as defined by IP >>> five-tuples) with different characteristics (number of flows, number of >>> packets, fragmentation thresholds). Currently pcap files are generated, >>> perhaps it should also be possible to transmit the packets (on some >>> interface) as they are generated. If we would have a demo application >>> implementing e.g. NAT, we would need to generate suitable packet traces and >>> not just ping/UDP-echo-type traffic. >>> >>> >>> >>> On 24 March 2014 10:23, Weilong Chen <weilong.chen@linaro.org> wrote: >>> >>>> Thanks! >>>> >>>> >>>> On 22 March 2014 01:13, Stuart Haslam <stuart.haslam@arm.com> wrote: >>>> >>>>> On Fri, Mar 21, 2014 at 03:09:17PM +0000, Mike Holmes wrote: >>>>> > Stuart, there are already a number of cards to increase this tools >>>>> > utility, and feature requests are eagerly sought, but this is just >>>>> the >>>>> > first evolution beyond the demo ping app. >>>>> > >>>>> > I think it should form a significant role in our testing when >>>>> > complete. >>>>> > >>>>> >>>>> [my mailer seems to have mangled the previous message.. trying again :] >>>>> >>>>> OK, sounds good. By the way, there's a pktgen tool for DPDK here; >>>>> https://github.com/Pktgen/Pktgen-DPDK >>>>> >>>>> Some of my comments were about missing functionality, either in this >>>>> app >>>>> or in ODP in general, and fixes for those can/should be deferred (but >>>>> most were related to things that should be fixed even for the first >>>>> revision). >>>>> >>>>> -- >>>>> Stuart. >>>>> >>>>> >>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "LNG ODP Sub-team - lng-odp@linaro.org" group. >>>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to lng-odp+unsubscribe@linaro.org. >>>> To post to this group, send email to lng-odp@linaro.org. >>>> Visit this group at >>>> http://groups.google.com/a/linaro.org/group/lng-odp/. >>>> To view this discussion on the web visit >>>> https://groups.google.com/a/linaro.org/d/msgid/lng-odp/CAD0aSzk%2BM05Ua_vr%3D_cGyCmscbxbU-Tq4aNetBXgtG2gk8S5SQ%40mail.gmail.com<https://groups.google.com/a/linaro.org/d/msgid/lng-odp/CAD0aSzk%2BM05Ua_vr%3D_cGyCmscbxbU-Tq4aNetBXgtG2gk8S5SQ%40mail.gmail.com?utm_medium=email&utm_source=footer> >>>> . >>>> >>>> For more options, visit https://groups.google.com/a/linaro.org/d/optout >>>> . >>>> >>> >>> -- >>> You received this message because you are subscribed to the Google >>> Groups "LNG ODP Sub-team - lng-odp@linaro.org" group. >>> To unsubscribe from this group and stop receiving emails from it, send >>> an email to lng-odp+unsubscribe@linaro.org. >>> To post to this group, send email to lng-odp@linaro.org. >>> Visit this group at http://groups.google.com/a/linaro.org/group/lng-odp/ >>> . >>> To view this discussion on the web visit >>> https://groups.google.com/a/linaro.org/d/msgid/lng-odp/CAPiYAf6C-pdwX4G_8kEN_auwWGD14M_wmk5HdBnnGoKMjU7tbg%40mail.gmail.com<https://groups.google.com/a/linaro.org/d/msgid/lng-odp/CAPiYAf6C-pdwX4G_8kEN_auwWGD14M_wmk5HdBnnGoKMjU7tbg%40mail.gmail.com?utm_medium=email&utm_source=footer> >>> . >>> >>> For more options, visit https://groups.google.com/a/linaro.org/d/optout. >>> >> >> >
Ok, then we can just add them to a git repo and use them. On 24 March 2014 08:35, Ola Liljedahl <ola.liljedahl@linaro.org> wrote: > My packet generators are not utilizing ODP, performance and scalability > have not been an issue for me. I wasn't thinking of using them as demo apps > for ODP, just for generating suitable traffic for the actual demo. > > > On 24 March 2014 13:30, Ola Liljedahl <ola.liljedahl@linaro.org> wrote: > >> What is required in order to comply with this "ODP/test format"? >> If I try to mimic odp-generator (?), will I be close then? >> I will likely need help from some other engineer. I do have some other >> things to work on which I think are more important (to me and ARM). >> >> >> On 24 March 2014 13:14, Mike Holmes <mike.holmes@linaro.org> wrote: >> >>> Thanks Ola, >>> >>> Will you be able to get them into a format that can be submitted to >>> ODP/test or will they need work by another Engineer? >>> >>> Mike >>> >>> >>> On 24 March 2014 08:10, Ola Liljedahl <ola.liljedahl@linaro.org> wrote: >>> >>>> I have a couple of packet generation tools that I could contribute (yes >>>> it is allowed now! just three months of waiting). >>>> >>>> My tools are more geared towards generating flows (as defined by IP >>>> five-tuples) with different characteristics (number of flows, number of >>>> packets, fragmentation thresholds). Currently pcap files are generated, >>>> perhaps it should also be possible to transmit the packets (on some >>>> interface) as they are generated. If we would have a demo application >>>> implementing e.g. NAT, we would need to generate suitable packet traces and >>>> not just ping/UDP-echo-type traffic. >>>> >>>> >>>> >>>> On 24 March 2014 10:23, Weilong Chen <weilong.chen@linaro.org> wrote: >>>> >>>>> Thanks! >>>>> >>>>> >>>>> On 22 March 2014 01:13, Stuart Haslam <stuart.haslam@arm.com> wrote: >>>>> >>>>>> On Fri, Mar 21, 2014 at 03:09:17PM +0000, Mike Holmes wrote: >>>>>> > Stuart, there are already a number of cards to increase this tools >>>>>> > utility, and feature requests are eagerly sought, but this is just >>>>>> the >>>>>> > first evolution beyond the demo ping app. >>>>>> > >>>>>> > I think it should form a significant role in our testing when >>>>>> > complete. >>>>>> > >>>>>> >>>>>> [my mailer seems to have mangled the previous message.. trying again >>>>>> :] >>>>>> >>>>>> OK, sounds good. By the way, there's a pktgen tool for DPDK here; >>>>>> https://github.com/Pktgen/Pktgen-DPDK >>>>>> >>>>>> Some of my comments were about missing functionality, either in this >>>>>> app >>>>>> or in ODP in general, and fixes for those can/should be deferred (but >>>>>> most were related to things that should be fixed even for the first >>>>>> revision). >>>>>> >>>>>> -- >>>>>> Stuart. >>>>>> >>>>>> >>>>> -- >>>>> You received this message because you are subscribed to the Google >>>>> Groups "LNG ODP Sub-team - lng-odp@linaro.org" group. >>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>> an email to lng-odp+unsubscribe@linaro.org. >>>>> To post to this group, send email to lng-odp@linaro.org. >>>>> Visit this group at >>>>> http://groups.google.com/a/linaro.org/group/lng-odp/. >>>>> To view this discussion on the web visit >>>>> https://groups.google.com/a/linaro.org/d/msgid/lng-odp/CAD0aSzk%2BM05Ua_vr%3D_cGyCmscbxbU-Tq4aNetBXgtG2gk8S5SQ%40mail.gmail.com<https://groups.google.com/a/linaro.org/d/msgid/lng-odp/CAD0aSzk%2BM05Ua_vr%3D_cGyCmscbxbU-Tq4aNetBXgtG2gk8S5SQ%40mail.gmail.com?utm_medium=email&utm_source=footer> >>>>> . >>>>> >>>>> For more options, visit >>>>> https://groups.google.com/a/linaro.org/d/optout. >>>>> >>>> >>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "LNG ODP Sub-team - lng-odp@linaro.org" group. >>>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to lng-odp+unsubscribe@linaro.org. >>>> To post to this group, send email to lng-odp@linaro.org. >>>> Visit this group at >>>> http://groups.google.com/a/linaro.org/group/lng-odp/. >>>> To view this discussion on the web visit >>>> https://groups.google.com/a/linaro.org/d/msgid/lng-odp/CAPiYAf6C-pdwX4G_8kEN_auwWGD14M_wmk5HdBnnGoKMjU7tbg%40mail.gmail.com<https://groups.google.com/a/linaro.org/d/msgid/lng-odp/CAPiYAf6C-pdwX4G_8kEN_auwWGD14M_wmk5HdBnnGoKMjU7tbg%40mail.gmail.com?utm_medium=email&utm_source=footer> >>>> . >>>> >>>> For more options, visit https://groups.google.com/a/linaro.org/d/optout >>>> . >>>> >>> >>> >> >
diff --git a/.gitignore b/.gitignore index 53454a5..91055bd 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ test/packet_netmap/odp_packet test/api_test/odp_atomic test/api_test/odp_shm test/api_test/odp_ring +test/generator/odp_generator diff --git a/test/Makefile b/test/Makefile index 2ff7a4c..771b3f4 100644 --- a/test/Makefile +++ b/test/Makefile @@ -9,6 +9,7 @@ all: $(MAKE) -C example $(MAKE) -C packet $(MAKE) -C packet_netmap + $(MAKE) -C generator .PHONY: clean clean: @@ -16,6 +17,7 @@ clean: $(MAKE) -C example clean $(MAKE) -C packet clean $(MAKE) -C packet_netmap clean + $(MAKE) -C generator clean .PHONY: install install: @@ -23,3 +25,4 @@ install: $(MAKE) -C example install $(MAKE) -C packet install $(MAKE) -C packet_netmap install + $(MAKE) -C generator install diff --git a/test/generator/Makefile b/test/generator/Makefile new file mode 100644 index 0000000..350d2e4 --- /dev/null +++ b/test/generator/Makefile @@ -0,0 +1,46 @@ +# Copyright (c) 2013, 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..0ec855b --- /dev/null +++ b/test/generator/odp_generator.c @@ -0,0 +1,847 @@ +/* Copyright (c) 2013, 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 <stdio.h> +#include<sys/time.h> + +#include <odp.h> +#include <helper/odp_packet_helper.h> +#include <helper/odp_linux.h> +#include <helper/odp_eth.h> +#include <helper/odp_ip.h> +#include <helper/odp_udp.h> +#include <odp_packet_io.h> + + +#define SHM_PKT_POOL_SIZE (512*2048) +#define SHM_PKT_POOL_BUF_SIZE 1856 + + +#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 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 */ +} appl_args_t; + +/** + * Thread specific arguments + */ +typedef struct { + char *pktio_dev; /**< Interface name to use */ + odp_buffer_pool_t pool; /**< Buffer pool for packet IO */ + int mode; /**< 0 send, 1 receive */ +} thread_args_t; + +/** + * Grouping of both parsed CL args and thread specific args - alloc together + */ +#define MAX_WORKERS 1 +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 */ +void tv_sub(struct timeval *recvtime,struct timeval *sendtime); +static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len); +static void print_pkts(odp_packet_t pkt_tbl[], unsigned len); +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); +unsigned int scan_ip(char *ip); +int scan_mac(char *in,char *des); +void compute_ip_checksum(odp_ipv4hdr_t *iphdrp); +void compute_udp_checksum(odp_ipv4hdr_t *pIph, unsigned short *ipPayload); + +/* args */ +char srcip[20]; +char dstip[20]; +char srcmac[20]; +char dstmac[20]; +int pksize = 0; +int interval = 1 * 1000; +int number = -1; //packets to send +int timeout = -1; //timeout seconds +int mode; //0 udp, 1 icmp, 2 r; +int ipcount; +int udpcount; +int icmpcount; +unsigned long long total; + +struct icmphdr { + u_int8_t type; /* message type */ + u_int8_t code; /* type sub-code */ + u_int16_t checksum; + u_int16_t id; + u_int16_t sequence; +}; + +/* parser ip */ +unsigned int scan_ip(char *ip) +{ + int part1,part2,part3,part4; + unsigned int ipi; + + sscanf(ip,"%d.%d.%d.%d",&part1,&part2,&part3,&part4); + ipi = 0; + ipi = part1 <<24 | part2 << 16| part3 << 8 | part4 ; + return ipi; +} + +/* parser mac */ +int scan_mac(char *in,char *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[i] = mac[i]; + } + + return field; +} + +static unsigned short pcount; + +/* Compute checksum for count bytes starting at addr, using one's complement of one's complement sum*/ +static unsigned short compute_checksum(unsigned short *addr, unsigned int count) +{ + register unsigned long sum = 0; + while (count > 1) { + sum += * addr++; + count -= 2; + } + //if any bytes left, pad the bytes and add + if(count > 0) { + sum += ((*addr)&odp_cpu_to_be_16(0xFF00)); + } + //Fold sum to 16 bits: add carrier to result + while (sum>>16) { + sum = (sum & 0xffff) + (sum >> 16); + } + //one's complement + sum = ~sum; + return ((unsigned short)sum); +} + +/* set ip checksum of a given ip header*/ +void compute_ip_checksum(odp_ipv4hdr_t *iphdrp) +{ + iphdrp->chksum = 0; + iphdrp->chksum = compute_checksum((unsigned short*)iphdrp, iphdrp->ver_ihl<<2); +} +void compute_udp_checksum(odp_ipv4hdr_t *pIph, unsigned short *ipPayload) +{ + register unsigned long sum = 0; + odp_udphdr_t *udphdrp = (odp_udphdr_t *)(ipPayload); + unsigned short udpLen = odp_cpu_to_be_16(udphdrp->length); + //the source ip + sum += (pIph->src_addr>>16)&0xFFFF; + sum += (pIph->src_addr)&0xFFFF; + //the dest ip + sum += (pIph->dst_addr>>16)&0xFFFF; + sum += (pIph->dst_addr)&0xFFFF; + sum += odp_cpu_to_be_16(ODP_IPPROTO_UDP); + //the length + sum += udphdrp->length; + + //initialize checksum to 0 + udphdrp->chksum = 0; + while (udpLen > 1) { + sum += * ipPayload++; + udpLen -= 2; + } + //if any bytes left, pad the bytes and add + if(udpLen > 0) { + sum += ((*ipPayload)&odp_cpu_to_be_16(0xFF00)); + } + //Fold sum to 16 bits: add carrier to result + //printf("add carrier\n"); + while (sum>>16) { + sum = (sum & 0xffff) + (sum >> 16); + } + //printf("one's complement\n"); + sum = ~sum; + //set computation result + udphdrp->chksum = ((unsigned short)sum == 0x0000)?0xFFFF:(unsigned short)sum; +} + +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; + + buf = odp_buffer_addr(obuf); + if(buf == NULL) + return; + max = odp_buffer_size(obuf); + if(max <= 0) + return; + + memset(buf, 0, max); + pkt = odp_packet_from_buffer(obuf); + //ether + odp_packet_set_l2_offset(pkt, 0); + eth = (odp_ethhdr_t *)buf; + scan_mac(dstmac,(char *)eth->dst.addr); + scan_mac(srcmac,(char *)eth->src.addr); + eth->type = odp_cpu_to_be_16 (ODP_ETHTYPE_IPV4); + //ip + odp_packet_set_l3_offset(pkt, 14); + ip = (odp_ipv4hdr_t *)(buf + 14); + ip->dst_addr = odp_cpu_to_be_32(scan_ip(dstip)); + ip->src_addr = odp_cpu_to_be_32(scan_ip(srcip)); + ip->ver_ihl = ODP_IPV4<<4|5; + ip->tot_len = odp_cpu_to_be_16(pksize + 8 + 20); + ip->proto = ODP_IPPROTO_UDP; + ip->id = odp_cpu_to_be_16(pcount++); + compute_ip_checksum(ip); + //udp + udp = (odp_udphdr_t *) (buf + 14 + 20); + udp->src_port = 0; + udp->dst_port = 0; + udp->length = odp_cpu_to_be_16(pksize + 8); + udp->chksum = 0; + compute_udp_checksum(ip, (unsigned short *)udp); + + odp_packet_set_len(pkt,pksize + 8 + 20 + 14); +} + +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; + struct icmphdr *icmp; + struct timeval *tval; + + buf = odp_buffer_addr(obuf); + if(buf == NULL) + return; + max = odp_buffer_size(obuf); + if(max <= 0) + return; + + memset(buf, 0, max); + pksize = 56; //set icmp size 56 + pkt = odp_packet_from_buffer(obuf); + //ether + odp_packet_set_l2_offset(pkt, 0); + eth = (odp_ethhdr_t *)buf; + scan_mac(dstmac,(char *)eth->dst.addr); + scan_mac(srcmac,(char *)eth->src.addr); + eth->type = odp_cpu_to_be_16 (ODP_ETHTYPE_IPV4); + //ip + odp_packet_set_l3_offset(pkt, 14); + ip = (odp_ipv4hdr_t *)(buf + 14); + ip->dst_addr = odp_cpu_to_be_32(scan_ip(dstip)); + ip->src_addr = odp_cpu_to_be_32(scan_ip(srcip)); + ip->ver_ihl = ODP_IPV4<<4|5; + ip->tot_len = odp_cpu_to_be_16(56 + 8 + 20); + ip->proto = ODP_IPPROTO_ICMP; + ip->id = odp_cpu_to_be_16(pcount++); + compute_ip_checksum(ip); + //icmp + icmp = (struct icmphdr *) (buf + 14 + 20); + icmp->type = 8; //Echo Request + icmp->code = 0; + icmp->id = odp_cpu_to_be_16(pcount - 1); + icmp->sequence = odp_cpu_to_be_16(pcount - 1); + tval = (struct timeval *)(buf + 14 + 20 + 8); + gettimeofday(tval,NULL); + icmp->checksum = 0; + icmp->checksum = compute_checksum((unsigned short *)icmp, 64); + + odp_packet_set_len(pkt,56 + 8 + 20 + 14); +} + + + +/** + * Packet IO loopback worker thread using ODP queues + * + * @param arg thread arguments of type 'thread_args_t *' + */ +static void *pktio_queue_thread(void *arg) +{ + int thr; + odp_buffer_pool_t pkt_pool; + odp_pktio_t pktio; + thread_args_t *thr_args; + odp_queue_t outq_def; + 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; + + if(mode == 1&& thr_args->mode != 2) + sleep(1); //wait receiver ok; + printf("Pktio thread [%02i] starts, pktio_dev:%s\n", thr, + thr_args->pktio_dev); + + /* Lookup the packet pool */ + pkt_pool = odp_buffer_pool_lookup("packet_pool"); + if (pkt_pool == ODP_BUFFER_POOL_INVALID) { + ODP_ERR(" [%02i] Error: pkt_pool not found\n", thr); + return NULL; + } + + /* Open a packet IO instance for this thread */ + sock_params->type = ODP_PKTIO_TYPE_SOCKET; + 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; + } + + if (thr_args->mode == 0 || thr_args->mode == 1) { + 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; + } + + for(;;) { + int err; + buf = odp_buffer_alloc(pkt_pool); + if (!odp_buffer_is_valid(buf)) { + ODP_ERR(" [%i] alloc_single failed\n", thr); + return NULL; + } + + if(thr_args->mode == 0) + pack_udp_pkt(buf); + else + pack_icmp_pkt(buf); + + err = odp_queue_enq(outq_def, buf); + total++; + if (err != 0) { + printf("send pkt err!\n"); + return NULL; + } + if(interval != 0) { //flood mode will not print msg + printf("Generator send pkt no:%llu seq %d size:%d\n", total,pcount - 1, pksize); + usleep(interval * 1000); + } else { + printf("Generator send pkt no:%llu seq %d size:%d\r", total,pcount - 1, pksize); + } + if (number != -1 && (int)total >= number) { + break; + } + + } + //if timeout >= 0; + while(mode == 1 && timeout >= 0) { + if(icmpcount >= number) + break; + sleep(1); + timeout--; + } + //print info: + if(mode == 0) { + printf("Total send:%llu\n",total); + } else if (mode == 1) { + printf("Total send:%llu,total receiver %d\n",total,icmpcount); + } + exit(0); + + } else if(thr_args->mode == 2) { + 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; + } + + for (;;) { + /* Use schedule to get buf from any input queue */ + buf = odp_schedule(NULL); + + pkt = odp_packet_from_buffer(buf); + /* Drop packets with errors */ + if (odp_unlikely(drop_err_pkts(&pkt, 1) == 0)) { + ODP_ERR("Drop frame\n"); + continue; + } + + /* Swap Eth MACs and possibly IP-addrs before sending back */ + print_pkts(&pkt, 1); + + odp_packet_free(pkt); + + } + + } + + return arg; +} + +/** + * Swap eth src<->dst and IP src<->dst addresses + * + * @param pkt_tbl Array of packets + * @param len Length of pkt_tbl[] + */ + +static void print_pkts(odp_packet_t pkt_tbl[], unsigned len) +{ + odp_packet_t pkt; + char *buf; + odp_ipv4hdr_t *ip; + odp_udphdr_t *udp; + struct icmphdr *icmp; + struct timeval tvrecv; + struct timeval *tvsend; + double rtt; + unsigned i; + char msg[1024]; + int rlen = 0; + FILE *stream; + for (i = 0; i < len; ++i) { + pkt = pkt_tbl[i]; + memset(msg, 0, 1024); + // print ip header + if(odp_packet_inflag_ipv4(pkt)) { + ipcount++; + 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)); + //ip = (odp_ipv4hdr_t *)odp_packet_l3(pkt); + rlen += sprintf(msg + rlen,"id %d ",odp_be_to_cpu_16(ip->id)); + + //udp + if(ip->proto == ODP_IPPROTO_UDP) { + udpcount++; + udp = (odp_udphdr_t *)(buf + odp_packet_l4_offset(pkt)); + rlen += sprintf(msg + rlen," UDP payload %d ",odp_be_to_cpu_16(udp->length) - 8); + } + + //icmp + if(ip->proto == ODP_IPPROTO_ICMP) { + icmp = (struct icmphdr *)(buf + odp_packet_l4_offset(pkt)); + if(icmp->type == 0) { + icmpcount++; + tvsend = (struct timeval *)(buf + odp_packet_l4_offset(pkt) + 8); + gettimeofday(&tvrecv,NULL); + tv_sub(&tvrecv,tvsend); + rtt = tvrecv.tv_sec*1000 + tvrecv.tv_usec/1000; + rlen += sprintf(msg + rlen, "ICMP seq %d time %.1f ",odp_be_to_cpu_16(icmp->sequence), rtt); + if(mode == 1) //ping mode + printf("%s\n",msg); + } + + } + if (mode == 2) //receiver mode + printf("%s\n",msg); + stream = fopen( "/tmp/recv.log", "a" ); + fprintf(stream, "Receive pkt NO:%d\n",odp_be_to_cpu_16(ip->id)); + fclose( stream ); + } + + } +} + +/** + * 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; + + /* Init ODP before calling anything else */ + if (odp_init_global()) { + ODP_ERR("Error: ODP global init failed.\n"); + exit(EXIT_FAILURE); + } + + /* 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); + + /* 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 (mode == 1) + num_workers = 2; + else + num_workers = 1; + + if (mode == 0) { + printf("Work mode: send udp packets\n\n"); + } else if (mode == 1) { + printf("Work mode: ping\n\n"); + } else if (mode == 2) { + printf("Work mode: receive ip packets\n\n"); + } else { + printf("Wrong mode\n"); + exit(EXIT_FAILURE); + } + for (i = 0; i < num_workers; ++i) { + void *(*thr_run_func) (void *); + int 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 = mode; + if(i == 1) + args->thread[i].mode = 2; + thr_run_func = pktio_queue_thread; + /* + * 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, i, 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 + */ +#pragma GCC diagnostic push // require GCC 4.6 +#pragma GCC diagnostic ignored "-Wcast-qual" +#pragma GCC diagnostic ignored "-Werror" +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'}, /* return 'i' */ + {"srcmac", required_argument, NULL, 'a'}, /* return 'm' */ + {"dstmac", required_argument, NULL, 'b'}, /* return 'm' */ + {"srcip", required_argument, NULL, 'c'}, /* return 'm' */ + {"dstip", required_argument, NULL, 'd'}, /* return 'm' */ + {"packetsize", required_argument, NULL, 's'}, /* return 'h' */ + {"mode", required_argument, NULL, 'm'}, + {"count", required_argument, NULL, 'n'}, + {"timeout", required_argument, NULL, 't'}, + {"interval", required_argument, NULL, 'i'}, /* return 'h' */ + {"help", no_argument, NULL, 'h'}, /* return 'h' */ + {NULL, 0, NULL, 0} + }; + + + while (1) { + opt = getopt_long(argc, argv, "+I:a:b:c:d:s:i:m:n:t:h", longopts, &long_index); + + if (opt == -1) + break; /* No more options */ + + switch (opt) { + /* 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 'a': + strcpy(srcmac, optarg); + break; + case 'b': + strcpy(dstmac, optarg); + break; + + case 'c': + strcpy(srcip, optarg); + break; + + case 'd': + strcpy(dstip, optarg); + break; + case 's': + pksize = atoi(optarg); + if(pksize > SHM_PKT_POOL_BUF_SIZE - 14 - 20 - 8) { + printf("the pksize is too big!\n"); + exit(EXIT_FAILURE); + } + break; + case 'm': + if(optarg[0] == 'u') { + mode = 0; + } else if (optarg[0] == 'p') { + mode = 1; + } else if (optarg[0] == 'r') { + mode = 2; + } else { + printf("wrong mode!\n"); + exit(EXIT_FAILURE); + } + break; + case 'n': + number = atoi(optarg); + break; + case 't': + timeout = atoi(optarg); + break; + case 'i': + interval = atoi(optarg); + if(interval <= 200 && geteuid() != 0) { + printf("Only super-user may set interval to values less 0.2 seconds.\n"); + exit(EXIT_FAILURE); + } + break; + case 'h': + usage(argv[0]); + exit(EXIT_SUCCESS); + break; + + default: + break; + } + } + + + optind = 1; /* reset 'extern optind' from the getopt lib */ +} +#pragma GCC diagnostic pop +/** + * 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 freq (hz): %"PRIu64"\n" + "Cache line size: %i\n" + "Core count: %i\n" + "\n", + odp_version_api_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\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 veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m u\n" + " 2.receive udp packets\n" + " 3.work likes ping\n" + " odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m p\n" + "\n" + "Mandatory OPTIONS:\n" + " -I, --interface Eth interfaces (comma-separated, no spaces)\n" + " -a, --srcmac src mac adddress\n" + " -b, --dstmac dst mac adddress\n" + " -c, --srcip src ip adddress\n" + " -d, --dstip dst ip adddress\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 floord mode\n" + "\n" + "Optional OPTIONS\n" + " -h, --help Display help and exit.\n" + "\n", NO_PATH(progname), NO_PATH(progname) + ); +} +/** + * Drop packets which input parsing marked as containing errors. + * + * Frees packets with error and modifies pkt_tbl[] to only contain packets with + * no detected errors. + * + * @param pkt_tbl Array of packet + * @param len Length of pkt_tbl[] + * + * @return Number of packets with no detected error + */ +static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len) +{ + odp_packet_t pkt; + unsigned pkt_cnt = len; + unsigned i, j; + + for (i = 0, j = 0; i < len; ++i) { + pkt = pkt_tbl[i]; + + if (odp_unlikely(odp_packet_error(pkt))) { + odp_packet_free(pkt); /* Drop */ + pkt_cnt--; + } else if (odp_unlikely(i != j++)) { + pkt_tbl[j] = pkt; + } + } + + return pkt_cnt; +} + +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 veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m u 2.receive udp packets odp_generator -I eth1 -r 3.work likes ping odp_generator -I veth0 -a fe:0f:97:c9:e0:44 -b 32:cb:9b:27:2f:1a -c 192.168.0.1 -d 192.168.0.2 -m p Signed-off-by: Weilong Chen <weilong.chen@linaro.org> --- .gitignore | 1 + test/Makefile | 3 + test/generator/Makefile | 46 +++ test/generator/odp_generator.c | 847 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 897 insertions(+) create mode 100644 test/generator/Makefile create mode 100644 test/generator/odp_generator.c