From patchwork Fri Mar 21 08:09:10 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Weilong Chen X-Patchwork-Id: 26793 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ve0-f199.google.com (mail-ve0-f199.google.com [209.85.128.199]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 084EB203AB for ; Fri, 21 Mar 2014 08:09:16 +0000 (UTC) Received: by mail-ve0-f199.google.com with SMTP id cz12sf4911904veb.2 for ; Fri, 21 Mar 2014 01:09:16 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:from:to:subject:date:message-id :x-original-sender:x-original-authentication-results:precedence :mailing-list:list-id:list-post:list-help:list-archive :list-unsubscribe:content-type; bh=TeECoc2l+DiBIgNUrg7MHs1hWrNKjFdEF+yhPJw+GGQ=; b=OWiVjHIsLa9dpGfergLX//MdG02T8PrRJQAOCPLaSJFkH0ZvAQnwk+PSgyaOwfgDxF zG1h42QvWLFve0CImdDwGZ6+ZFxcE9NtOKruqCygAQTgPVZqTV7GXy1o0NB06CW0rCu2 X4pLYewibktNQsNz31c2W3bLcE84zeFGbZfR+aDEFKzyZioWa1FALUVQ4zzpcgIb/kCl ZskRc8qHcDzcX1hC2+/iuIVo68fxp5vSAKj/vi2iShCRlFD2OtFZFgxTi+mwva18xNQ6 SiUtU6MxZEbodCCbjPLB1wr9pR6180SzxR2g/S59JZ5SoOGJYILqPslXbgv1jh7jIdGE EDNg== X-Gm-Message-State: ALoCoQluH+9SeKpt/3BJsXtt48gf4StVm/aqq//0BXkWI4WEt9FuMpMgsBIHS9Aun2fylyGAkEve X-Received: by 10.236.202.110 with SMTP id c74mr9427676yho.25.1395389356596; Fri, 21 Mar 2014 01:09:16 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: lng-odp@linaro.org Received: by 10.50.56.46 with SMTP id x14ls197667igp.5.canary; Fri, 21 Mar 2014 01:09:16 -0700 (PDT) X-Received: by 10.66.231.104 with SMTP id tf8mr53096211pac.48.1395389356150; Fri, 21 Mar 2014 01:09:16 -0700 (PDT) Received: from mail-pa0-f53.google.com (mail-pa0-f53.google.com [209.85.220.53]) by mx.google.com with ESMTPS id gu6si3199739pac.202.2014.03.21.01.09.16 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 21 Mar 2014 01:09:16 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.220.53 is neither permitted nor denied by best guess record for domain of weilong.chen@linaro.org) client-ip=209.85.220.53; Received: by mail-pa0-f53.google.com with SMTP id ld10so2064590pab.26 for ; Fri, 21 Mar 2014 01:09:16 -0700 (PDT) X-Received: by 10.66.164.229 with SMTP id yt5mr53118006pab.67.1395389355740; Fri, 21 Mar 2014 01:09:15 -0700 (PDT) Received: from localhost.localdomain ([218.17.215.175]) by mx.google.com with ESMTPSA id eb5sm22425588pad.22.2014.03.21.01.09.13 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 21 Mar 2014 01:09:15 -0700 (PDT) From: Weilong Chen To: lng-odp@linaro.org Subject: [lng-odp] [PATCH] Add a test program: odp_generator Date: Fri, 21 Mar 2014 16:09:10 +0800 Message-Id: <1395389350-12912-1-git-send-email-weilong.chen@linaro.org> X-Mailer: git-send-email 1.7.9.5 X-Original-Sender: weilong.chen@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.220.53 is neither permitted nor denied by best guess record for domain of weilong.chen@linaro.org) smtp.mail=weilong.chen@linaro.org Precedence: list Mailing-list: list lng-odp@linaro.org; contact lng-odp+owners@linaro.org List-ID: X-Google-Group-Id: 474323889996 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , 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 --- .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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#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; + } +}