diff options
Diffstat (limited to 'example/generator/odp_generator.c')
-rw-r--r-- | example/generator/odp_generator.c | 538 |
1 files changed, 374 insertions, 164 deletions
diff --git a/example/generator/odp_generator.c b/example/generator/odp_generator.c index 8062d8733..9336cec16 100644 --- a/example/generator/odp_generator.c +++ b/example/generator/odp_generator.c @@ -26,6 +26,8 @@ #define POOL_NUM_PKT 2048 /* Number of packets in packet pool */ #define POOL_PKT_LEN 1856 /* Max packet length */ #define DEFAULT_PKT_INTERVAL 1000 /* Interval between each packet */ +#define MAX_UDP_TX_BURST 32 +#define MAX_RX_BURST 32 #define APPL_MODE_UDP 0 /**< UDP mode */ #define APPL_MODE_PING 1 /**< ping mode */ @@ -37,6 +39,17 @@ /** 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)) + +/** + * Interfaces + */ + +typedef struct { + odp_pktio_t pktio; + odp_pktout_queue_t pktout[MAX_WORKERS]; + unsigned pktout_count; +} interface_t; + /** * Parsed command line application arguments */ @@ -51,12 +64,16 @@ typedef struct { odph_ethaddr_t dstmac; /**< dest mac addr */ unsigned int srcip; /**< src ip addr */ unsigned int dstip; /**< dest ip addr */ + uint16_t srcport; /**< src udp port */ + uint16_t dstport; /**< dest udp port */ int mode; /**< work mode */ int number; /**< packets number to be sent */ int payload; /**< data len */ int timeout; /**< wait time */ int interval; /**< wait interval ms between sending each packet */ + int udp_tx_burst; /**< number of udp packets to send with one + API call */ } appl_args_t; /** @@ -74,7 +91,7 @@ static struct { /** * Thread specific arguments */ typedef struct { - char *pktio_dev; /**< Interface name to use */ + odp_pktout_queue_t pktout; /**< Packet output queue to use*/ odp_pool_t pool; /**< Pool for packet IO */ odp_timer_pool_t tp; /**< Timer pool handle */ odp_queue_t tq; /**< Queue for timeouts */ @@ -104,7 +121,6 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args); static void print_info(char *progname, appl_args_t *appl_args); static void usage(char *progname); static int scan_ip(char *buf, unsigned int *paddr); -static void tv_sub(struct timeval *recvtime, struct timeval *sendtime); static void print_global_stats(int num_workers); /** @@ -170,21 +186,20 @@ static int scan_ip(char *buf, unsigned int *paddr) } /** - * set up an udp packet + * set up an udp packet reference * * @param pool Buffer pool to create packet in * * @return Handle of created packet * @retval ODP_PACKET_INVALID Packet could not be created */ -static odp_packet_t pack_udp_pkt(odp_pool_t pool) +static odp_packet_t setup_udp_pkt_ref(odp_pool_t pool) { odp_packet_t pkt; char *buf; odph_ethhdr_t *eth; odph_ipv4hdr_t *ip; odph_udphdr_t *udp; - unsigned short seq; pkt = odp_packet_alloc(pool, args->appl.payload + ODPH_UDPHDR_LEN + ODPH_IPV4HDR_LEN + ODPH_ETHHDR_LEN); @@ -200,8 +215,10 @@ static odp_packet_t pack_udp_pkt(odp_pool_t pool) memcpy((char *)eth->src.addr, args->appl.srcmac.addr, ODPH_ETHADDR_LEN); memcpy((char *)eth->dst.addr, args->appl.dstmac.addr, ODPH_ETHADDR_LEN); eth->type = odp_cpu_to_be_16(ODPH_ETHTYPE_IPV4); + /* ip */ odp_packet_l3_offset_set(pkt, ODPH_ETHHDR_LEN); + odp_packet_has_ipv4_set(pkt, 1); ip = (odph_ipv4hdr_t *)(buf + ODPH_ETHHDR_LEN); ip->dst_addr = odp_cpu_to_be_32(args->appl.dstip); ip->src_addr = odp_cpu_to_be_32(args->appl.srcip); @@ -209,15 +226,16 @@ static odp_packet_t pack_udp_pkt(odp_pool_t pool) ip->tot_len = odp_cpu_to_be_16(args->appl.payload + ODPH_UDPHDR_LEN + ODPH_IPV4HDR_LEN); ip->proto = ODPH_IPPROTO_UDP; - seq = odp_atomic_fetch_add_u64(&counters.seq, 1) % 0xFFFF; - ip->id = odp_cpu_to_be_16(seq); + ip->id = 0; + ip->ttl = 64; ip->chksum = 0; - odph_ipv4_csum_update(pkt); + /* udp */ odp_packet_l4_offset_set(pkt, ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN); + odp_packet_has_udp_set(pkt, 1); udp = (odph_udphdr_t *)(buf + ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN); - udp->src_port = 0; - udp->dst_port = 0; + udp->src_port = odp_cpu_to_be_16(args->appl.srcport); + udp->dst_port = odp_cpu_to_be_16(args->appl.dstport); udp->length = odp_cpu_to_be_16(args->appl.payload + ODPH_UDPHDR_LEN); udp->chksum = 0; udp->chksum = odph_ipv4_udp_chksum(pkt); @@ -226,27 +244,60 @@ static odp_packet_t pack_udp_pkt(odp_pool_t pool) } /** - * Set up an icmp packet + * set up an udp packet * * @param pool Buffer pool to create packet in + * @param pkt_ref Reference UDP packet * * @return Handle of created packet * @retval ODP_PACKET_INVALID Packet could not be created */ -static odp_packet_t pack_icmp_pkt(odp_pool_t pool) +static odp_packet_t pack_udp_pkt(odp_pool_t pool, odp_packet_t pkt_ref) +{ + odp_packet_t pkt; + char *buf; + odph_ipv4hdr_t *ip; + unsigned short seq; + + pkt = odp_packet_alloc(pool, args->appl.payload + ODPH_UDPHDR_LEN + + ODPH_IPV4HDR_LEN + ODPH_ETHHDR_LEN); + + if (pkt == ODP_PACKET_INVALID) + return pkt; + + buf = (char *)odp_packet_data(pkt); + odp_memcpy(buf, odp_packet_data(pkt_ref), + args->appl.payload + ODPH_UDPHDR_LEN + + ODPH_IPV4HDR_LEN + ODPH_ETHHDR_LEN); + + /*Update IP ID and checksum*/ + ip = (odph_ipv4hdr_t *)(buf + ODPH_ETHHDR_LEN); + seq = odp_atomic_fetch_add_u64(&counters.seq, 1) % 0xFFFF; + ip->id = odp_cpu_to_be_16(seq); + ip->chksum = odph_chksum(ip, ODPH_IPV4HDR_LEN); + + return pkt; +} + +/** + * Set up an icmp packet reference + * + * @param pool Buffer pool to create packet in + * + * @return Handle of created packet + * @retval ODP_PACKET_INVALID Packet could not be created + */ +static odp_packet_t setup_icmp_pkt_ref(odp_pool_t pool) { odp_packet_t pkt; char *buf; odph_ethhdr_t *eth; odph_ipv4hdr_t *ip; odph_icmphdr_t *icmp; - struct timeval tval; - uint8_t *tval_d; - unsigned short seq; args->appl.payload = 56; pkt = odp_packet_alloc(pool, args->appl.payload + ODPH_ICMPHDR_LEN + - ODPH_IPV4HDR_LEN + ODPH_ETHHDR_LEN); + ODPH_IPV4HDR_LEN + ODPH_ETHHDR_LEN); if (pkt == ODP_PACKET_INVALID) return pkt; @@ -265,25 +316,69 @@ static odp_packet_t pack_icmp_pkt(odp_pool_t pool) ip->dst_addr = odp_cpu_to_be_32(args->appl.dstip); ip->src_addr = odp_cpu_to_be_32(args->appl.srcip); ip->ver_ihl = ODPH_IPV4 << 4 | ODPH_IPV4HDR_IHL_MIN; + ip->ttl = 64; ip->tot_len = odp_cpu_to_be_16(args->appl.payload + ODPH_ICMPHDR_LEN + ODPH_IPV4HDR_LEN); - ip->proto = ODPH_IPPROTO_ICMP; - seq = odp_atomic_fetch_add_u64(&counters.seq, 1) % 0xffff; - ip->id = odp_cpu_to_be_16(seq); + ip->proto = ODPH_IPPROTO_ICMPv4; + ip->id = 0; ip->chksum = 0; - odph_ipv4_csum_update(pkt); + /* icmp */ icmp = (odph_icmphdr_t *)(buf + ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN); icmp->type = ICMP_ECHO; icmp->code = 0; icmp->un.echo.id = 0; + icmp->un.echo.sequence = 0; + icmp->chksum = 0; + + return pkt; +} + +/** + * Set up an icmp packet + * + * @param pool Buffer pool to create packet in + * @param pkt_ref Reference ICMP packet + * + * @return Handle of created packet + * @retval ODP_PACKET_INVALID Packet could not be created + */ +static odp_packet_t pack_icmp_pkt(odp_pool_t pool, odp_packet_t pkt_ref) +{ + odp_packet_t pkt; + char *buf; + odph_ipv4hdr_t *ip; + odph_icmphdr_t *icmp; + uint64_t tval; + uint8_t *tval_d; + unsigned short seq; + + pkt = odp_packet_alloc(pool, args->appl.payload + ODPH_ICMPHDR_LEN + + ODPH_IPV4HDR_LEN + ODPH_ETHHDR_LEN); + + if (pkt == ODP_PACKET_INVALID) + return pkt; + + buf = (char *)odp_packet_data(pkt); + odp_memcpy(buf, odp_packet_data(pkt_ref), + args->appl.payload + ODPH_ICMPHDR_LEN + + ODPH_IPV4HDR_LEN + ODPH_ETHHDR_LEN); + + /* ip */ + ip = (odph_ipv4hdr_t *)(buf + ODPH_ETHHDR_LEN); + seq = odp_atomic_fetch_add_u64(&counters.seq, 1) % 0xffff; + ip->id = odp_cpu_to_be_16(seq); + ip->chksum = odph_chksum(ip, ODPH_IPV4HDR_LEN); + + /* icmp */ + icmp = (odph_icmphdr_t *)(buf + ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN); icmp->un.echo.sequence = ip->id; + tval_d = (uint8_t *)(buf + ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN + ODPH_ICMPHDR_LEN); - /* TODO This should be changed to use an - * ODP timer API once one exists. */ - gettimeofday(&tval, NULL); - memcpy(tval_d, &tval, sizeof(struct timeval)); + tval = odp_time_to_ns(odp_time_local()); + memcpy(tval_d, &tval, sizeof(uint64_t)); + icmp->chksum = 0; icmp->chksum = odph_chksum(icmp, args->appl.payload + ODPH_ICMPHDR_LEN); @@ -299,48 +394,80 @@ static odp_packet_t pack_icmp_pkt(odp_pool_t pool) * @return The handle of the created pktio object. * @warning This routine aborts if the create is unsuccessful. */ -static odp_pktio_t create_pktio(const char *dev, odp_pool_t pool) +static int create_pktio(const char *dev, odp_pool_t pool, + unsigned num_rx_queues, + unsigned num_tx_queues, + interface_t *itf) { - odp_pktio_t pktio; + odp_pktio_capability_t capa; int ret; odp_pktio_param_t pktio_param; odp_pktin_queue_param_t pktin_param; + odp_pktout_queue_param_t pktout_param; + odp_pktio_op_mode_t pktout_mode; odp_pktio_param_init(&pktio_param); pktio_param.in_mode = ODP_PKTIN_MODE_SCHED; /* Open a packet IO instance */ - pktio = odp_pktio_open(dev, pool, &pktio_param); + itf->pktio = odp_pktio_open(dev, pool, &pktio_param); - if (pktio == ODP_PKTIO_INVALID) { + if (itf->pktio == ODP_PKTIO_INVALID) { EXAMPLE_ERR("Error: pktio create failed for %s\n", dev); - exit(EXIT_FAILURE); + return -1; + } + + if (odp_pktio_capability(itf->pktio, &capa)) { + EXAMPLE_ERR("Error: Failed to get interface capabilities %s\n", + dev); + return -1; } + if (num_rx_queues > capa.max_input_queues) + num_rx_queues = capa.max_input_queues; odp_pktin_queue_param_init(&pktin_param); + pktin_param.num_queues = num_rx_queues; pktin_param.queue_param.sched.sync = ODP_SCHED_SYNC_ATOMIC; - if (odp_pktin_queue_config(pktio, &pktin_param)) { + if (odp_pktin_queue_config(itf->pktio, &pktin_param)) { EXAMPLE_ERR("Error: pktin queue config failed for %s\n", dev); - exit(EXIT_FAILURE); + return -1; } - if (odp_pktout_queue_config(pktio, NULL)) { + pktout_mode = ODP_PKTIO_OP_MT_UNSAFE; + if (num_tx_queues > capa.max_output_queues) { + num_tx_queues = capa.max_output_queues; + pktout_mode = ODP_PKTIO_OP_MT; + } + + odp_pktout_queue_param_init(&pktout_param); + pktout_param.num_queues = num_tx_queues; + pktout_param.op_mode = pktout_mode; + + if (odp_pktout_queue_config(itf->pktio, &pktout_param)) { EXAMPLE_ERR("Error: pktout queue config failed for %s\n", dev); - exit(EXIT_FAILURE); + return -1; } - ret = odp_pktio_start(pktio); + ret = odp_pktio_start(itf->pktio); if (ret) EXAMPLE_ABORT("Error: unable to start %s\n", dev); + itf->pktout_count = num_tx_queues; + if (odp_pktout_queue(itf->pktio, itf->pktout, itf->pktout_count) != + (int)itf->pktout_count) { + EXAMPLE_ERR("Error: failed to get output queues for %s\n", dev); + return -1; + } + printf(" created pktio:%02" PRIu64 ", dev:%s, queue mode (ATOMIC queues)\n" " default pktio%02" PRIu64 "\n", - odp_pktio_to_u64(pktio), dev, - odp_pktio_to_u64(pktio)); + odp_pktio_to_u64(itf->pktio), dev, + odp_pktio_to_u64(itf->pktio)); + fflush(NULL); - return pktio; + return 0; } /** @@ -352,24 +479,33 @@ static odp_pktio_t create_pktio(const char *dev, odp_pool_t pool) static int gen_send_thread(void *arg) { int thr; - int ret; - odp_pktio_t pktio; + int ret, i; thread_args_t *thr_args; odp_pktout_queue_t pktout; - odp_packet_t pkt; + odp_packet_t pkt_array[MAX_UDP_TX_BURST]; + int pkt_array_size; + int burst_start, burst_size; + odp_packet_t pkt_ref = ODP_PACKET_INVALID; thr = odp_thread_id(); thr_args = arg; - pktio = odp_pktio_lookup(thr_args->pktio_dev); - if (pktio == ODP_PKTIO_INVALID) { - EXAMPLE_ERR(" [%02i] Error: lookup of pktio %s failed\n", - thr, thr_args->pktio_dev); + pktout = thr_args->pktout; + + if (args->appl.mode == APPL_MODE_UDP) { + pkt_ref = setup_udp_pkt_ref(thr_args->pool); + pkt_array_size = args->appl.udp_tx_burst; + } else if (args->appl.mode == APPL_MODE_PING) { + pkt_ref = setup_icmp_pkt_ref(thr_args->pool); + pkt_array_size = 1; + } else { + EXAMPLE_ERR(" [%02i] Error: invalid processing mode %d\n", + thr, args->appl.mode); return -1; } - - if (odp_pktout_queue(pktio, &pktout, 1) != 1) { - EXAMPLE_ERR(" [%02i] Error: no output queue\n", thr); + if (pkt_ref == ODP_PACKET_INVALID) { + EXAMPLE_ERR(" [%2i] Error: reference packet creation failed\n", + thr); return -1; } @@ -379,36 +515,50 @@ static int gen_send_thread(void *arg) for (;;) { if (args->appl.number != -1 && - odp_atomic_fetch_add_u64(&counters.cnt, 1) >= - (unsigned int)args->appl.number) + odp_atomic_fetch_add_u64(&counters.cnt, pkt_array_size) >= + (unsigned int)args->appl.number) break; - pkt = ODP_PACKET_INVALID; - - if (args->appl.mode == APPL_MODE_UDP) - pkt = pack_udp_pkt(thr_args->pool); - else if (args->appl.mode == APPL_MODE_PING) - pkt = pack_icmp_pkt(thr_args->pool); - - if (pkt == ODP_PACKET_INVALID) { - /* Thread gives up as soon as it sees the pool empty. - * Depending on pool size and transmit latency, it may - * be normal that pool gets empty sometimes. */ - EXAMPLE_ERR(" [%2i] alloc_single failed\n", thr); + if (args->appl.mode == APPL_MODE_UDP) { + for (i = 0; i < pkt_array_size; i++) { + pkt_array[i] = pack_udp_pkt(thr_args->pool, + pkt_ref); + if (!odp_packet_is_valid(pkt_array[i])) + break; + } + if (i != pkt_array_size) { + EXAMPLE_ERR(" [%2i] alloc_multi failed\n", + thr); + odp_packet_free_multi(pkt_array, i); + break; + } + } else if (args->appl.mode == APPL_MODE_PING) { + pkt_array[0] = pack_icmp_pkt(thr_args->pool, pkt_ref); + if (!odp_packet_is_valid(pkt_array[0])) { + EXAMPLE_ERR(" [%2i] alloc_single failed\n", + thr); + break; + } + } else { break; } - for (;;) { - ret = odp_pktout_send(pktout, &pkt, 1); - if (ret == 1) { + for (burst_start = 0, burst_size = pkt_array_size;;) { + ret = odp_pktout_send(pktout, &pkt_array[burst_start], + burst_size); + if (ret == burst_size) { break; - } else if (ret == 0) { - odp_atomic_add_u64(&counters.tx_drops, 1); + } else if (ret >= 0 && ret < burst_size) { + odp_atomic_add_u64(&counters.tx_drops, + burst_size - ret); + burst_start += ret; + burst_size -= ret; odp_time_wait_ns(ODP_TIME_MSEC_IN_NS); continue; } EXAMPLE_ERR(" [%02i] packet send failed\n", thr); - odp_packet_free(pkt); + odp_packet_free_multi(&pkt_array[burst_start], + burst_size); break; } @@ -440,11 +590,46 @@ static int gen_send_thread(void *arg) args->appl.timeout--; } } + odp_packet_free(pkt_ref); return 0; } /** + * Process icmp packets + * + * @param icmp icmp header address + * @param msg output buffer + */ + +static void process_icmp_pkt(odph_icmphdr_t *icmp, char *msg) +{ + uint64_t trecv; + uint64_t tsend; + uint64_t rtt_ms, rtt_us; + + msg[0] = 0; + + if (icmp->type == ICMP_ECHOREPLY) { + odp_atomic_inc_u64(&counters.icmp); + + memcpy(&tsend, (uint8_t *)icmp + ODPH_ICMPHDR_LEN, + sizeof(uint64_t)); + trecv = odp_time_to_ns(odp_time_local()); + rtt_ms = (trecv - tsend) / ODP_TIME_MSEC_IN_NS; + rtt_us = (trecv - tsend) / ODP_TIME_USEC_IN_NS - + 1000 * rtt_ms; + sprintf(msg, + "ICMP Echo Reply seq %d time %" + PRIu64 ".%.03" PRIu64" ms", + odp_be_to_cpu_16(icmp->un.echo.sequence), + rtt_ms, rtt_us); + } else if (icmp->type == ICMP_ECHO) { + sprintf(msg, "Icmp Echo Request"); + } +} + +/** * Print odp packets * * @param thr worker id @@ -457,16 +642,12 @@ static void print_pkts(int thr, odp_packet_t pkt_tbl[], unsigned len) char *buf; odph_ipv4hdr_t *ip; odph_icmphdr_t *icmp; - struct timeval tvrecv; - struct timeval tvsend; - double rtt; unsigned i; size_t offset; char msg[1024]; - int rlen; + for (i = 0; i < len; ++i) { pkt = pkt_tbl[i]; - rlen = 0; /* only ip pkts */ if (!odp_packet_has_ipv4(pkt)) @@ -483,28 +664,10 @@ static void print_pkts(int thr, odp_packet_t pkt_tbl[], unsigned len) } /* icmp */ - if (ip->proto == ODPH_IPPROTO_ICMP) { + if (ip->proto == ODPH_IPPROTO_ICMPv4) { icmp = (odph_icmphdr_t *)(buf + offset); - /* echo reply */ - if (icmp->type == ICMP_ECHOREPLY) { - odp_atomic_inc_u64(&counters.icmp); - memcpy(&tvsend, buf + offset + ODPH_ICMPHDR_LEN, - sizeof(struct timeval)); - /* TODO This should be changed to use an - * ODP timer API once one exists. */ - gettimeofday(&tvrecv, NULL); - tv_sub(&tvrecv, &tvsend); - rtt = tvrecv.tv_sec*1000 + tvrecv.tv_usec/1000; - rlen += sprintf(msg + rlen, - "ICMP Echo Reply seq %d time %.1f ", - odp_be_to_cpu_16(icmp->un.echo.sequence) - , rtt); - } else if (icmp->type == ICMP_ECHO) { - rlen += sprintf(msg + rlen, - "Icmp Echo Request"); - } - msg[rlen] = '\0'; + process_icmp_pkt(icmp, msg); printf(" [%02i] %s\n", thr, msg); } } @@ -518,20 +681,12 @@ static void print_pkts(int thr, odp_packet_t pkt_tbl[], unsigned len) static int gen_recv_thread(void *arg) { int thr; - odp_pktio_t pktio; - thread_args_t *thr_args; - odp_packet_t pkt; - odp_event_t ev; + odp_packet_t pkts[MAX_RX_BURST], pkt; + odp_event_t events[MAX_RX_BURST]; + int pkt_cnt, ev_cnt, i; thr = odp_thread_id(); - thr_args = arg; - - pktio = odp_pktio_lookup(thr_args->pktio_dev); - if (pktio == ODP_PKTIO_INVALID) { - EXAMPLE_ERR(" [%02i] Error: lookup of pktio %s failed\n", - thr, thr_args->pktio_dev); - return -1; - } + (void)arg; printf(" [%02i] created mode: RECEIVE\n", thr); odp_barrier_wait(&barrier); @@ -544,18 +699,24 @@ static int gen_recv_thread(void *arg) } /* Use schedule to get buf from any input queue */ - ev = odp_schedule(NULL, ODP_SCHED_WAIT); - - pkt = odp_packet_from_event(ev); - /* Drop packets with errors */ - if (odp_unlikely(odp_packet_has_error(pkt))) { - odp_packet_free(pkt); + ev_cnt = odp_schedule_multi(NULL, ODP_SCHED_WAIT, + events, MAX_RX_BURST); + if (ev_cnt == 0) continue; + for (i = 0, pkt_cnt = 0; i < ev_cnt; i++) { + pkt = odp_packet_from_event(events[i]); + + /* Drop packets with errors */ + if (odp_unlikely(odp_packet_has_error(pkt))) { + odp_packet_free(pkt); + continue; + } + pkts[pkt_cnt++] = pkt; } - print_pkts(thr, &pkt, 1); + print_pkts(thr, pkts, pkt_cnt); - odp_packet_free(pkt); + odp_packet_free_multi(pkts, pkt_cnt); } return 0; @@ -568,7 +729,10 @@ static int gen_recv_thread(void *arg) static void print_global_stats(int num_workers) { odp_time_t cur, wait, next; - uint64_t pkts, pkts_prev = 0, pps, maximum_pps = 0; + uint64_t pkts_snd = 0, pkts_snd_prev = 0; + uint64_t pps_snd = 0, maximum_pps_snd = 0; + uint64_t pkts_rcv = 0, pkts_rcv_prev = 0; + uint64_t pps_rcv = 0, maximum_pps_rcv = 0; int verbose_interval = 20; odp_thrmask_t thrd_mask; @@ -589,30 +753,41 @@ static void print_global_stats(int num_workers) continue; next = odp_time_sum(cur, wait); - - if (args->appl.mode == APPL_MODE_RCV) { - pkts = odp_atomic_load_u64(&counters.udp); - printf(" total receive(UDP: %" PRIu64 ")\n", pkts); + switch (args->appl.mode) { + case APPL_MODE_RCV: + pkts_rcv = odp_atomic_load_u64(&counters.ip); + break; + case APPL_MODE_PING: + pkts_snd = odp_atomic_load_u64(&counters.seq); + pkts_rcv = odp_atomic_load_u64(&counters.icmp); + break; + case APPL_MODE_UDP: + pkts_snd = odp_atomic_load_u64(&counters.seq); + break; + default: continue; } - if (args->appl.mode == APPL_MODE_PING) { - pkts = odp_atomic_load_u64(&counters.icmp); - printf(" total receive(ICMP: %" PRIu64 ")\n", pkts); - } - - pkts = odp_atomic_load_u64(&counters.seq); - printf(" total sent: %" PRIu64 ", drops: %" PRIu64 "\n", pkts, - odp_atomic_load_u64(&counters.tx_drops)); - - if (args->appl.mode == APPL_MODE_UDP) { - pps = (pkts - pkts_prev) / verbose_interval; - if (pps > maximum_pps) - maximum_pps = pps; - printf(" %" PRIu64 " pps, %" PRIu64 " max pps\n", - pps, maximum_pps); - pkts_prev = pkts; - } + pps_snd = (pkts_snd - pkts_snd_prev) / verbose_interval; + pkts_snd_prev = pkts_snd; + if (pps_snd > maximum_pps_snd) + maximum_pps_snd = pps_snd; + + pps_rcv = (pkts_rcv - pkts_rcv_prev) / verbose_interval; + pkts_rcv_prev = pkts_rcv; + if (pps_rcv > maximum_pps_rcv) + maximum_pps_rcv = pps_rcv; + + printf("sent: %" PRIu64 ", drops: %" PRIu64 ", " + "send rate: %" PRIu64 " pps, " + "max send rate: %" PRIu64 " pps, " + "rcv: %" PRIu64 ", " + "recv rate: %" PRIu64 " pps, " + "max recv rate: %" PRIu64 " pps\n", + pkts_snd, odp_atomic_load_u64(&counters.tx_drops), + pps_snd, maximum_pps_snd, + pkts_rcv, pps_rcv, maximum_pps_rcv); + fflush(NULL); } } @@ -624,6 +799,7 @@ int main(int argc, char *argv[]) odph_odpthread_t thread_tbl[MAX_WORKERS]; odp_pool_t pool; int num_workers; + unsigned num_rx_queues, num_tx_queues; int i; odp_shm_t shm; odp_cpumask_t cpumask; @@ -634,7 +810,7 @@ int main(int argc, char *argv[]) odp_pool_t tmop; odp_queue_t tq; odp_event_t ev; - odp_pktio_t *pktio; + interface_t *ifs; odp_instance_t instance; odph_odpthread_params_t thr_params; @@ -694,6 +870,7 @@ int main(int argc, char *argv[]) printf("num worker threads: %i\n", num_workers); printf("first CPU: %i\n", odp_cpumask_first(&cpumask)); printf("cpu mask: %s\n", cpumaskstr); + fflush(NULL); /* ping mode need two workers */ if (args->appl.mode == APPL_MODE_PING) { @@ -745,10 +922,30 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } - pktio = malloc(sizeof(odp_pktio_t) * args->appl.if_count); + ifs = malloc(sizeof(interface_t) * args->appl.if_count); + + if (args->appl.mode == APPL_MODE_PING || + args->appl.mode == APPL_MODE_UDP) + num_rx_queues = 1; + else + num_rx_queues = num_workers; + + if (args->appl.mode == APPL_MODE_PING || + args->appl.mode == APPL_MODE_RCV) + num_tx_queues = 1; + else { + num_tx_queues = num_workers / args->appl.if_count; + if (num_workers % args->appl.if_count) + num_tx_queues++; + } for (i = 0; i < args->appl.if_count; ++i) - pktio[i] = create_pktio(args->appl.if_names[i], pool); + if (create_pktio(args->appl.if_names[i], pool, num_rx_queues, + num_tx_queues, &ifs[i])) { + EXAMPLE_ERR("Error: create interface %s failed.\n", + args->appl.if_names[i]); + exit(EXIT_FAILURE); + } /* Create and init worker threads */ memset(thread_tbl, 0, sizeof(thread_tbl)); @@ -774,7 +971,7 @@ int main(int argc, char *argv[]) EXAMPLE_ERR("queue_create failed\n"); abort(); } - args->thread[1].pktio_dev = args->appl.if_names[0]; + (void)args->thread[1].pktout; /* Not used*/ args->thread[1].pool = pool; args->thread[1].tp = tp; args->thread[1].tq = tq; @@ -803,7 +1000,7 @@ int main(int argc, char *argv[]) EXAMPLE_ERR("queue_create failed\n"); abort(); } - args->thread[0].pktio_dev = args->appl.if_names[0]; + args->thread[0].pktout = ifs[0].pktout[0]; args->thread[0].pool = pool; args->thread[0].tp = tp; args->thread[0].tq = tq; @@ -829,14 +1026,22 @@ int main(int argc, char *argv[]) } else { int cpu = odp_cpumask_first(&cpumask); + for (i = 0; i < num_workers; ++i) { odp_cpumask_t thd_mask; int (*thr_run_func)(void *); - int if_idx; + int if_idx, pktout_idx; - if_idx = i % args->appl.if_count; + if (args->appl.mode == APPL_MODE_RCV) + (void)args->thread[i].pktout; /*not used*/ + else { + if_idx = i % args->appl.if_count; + pktout_idx = (i / args->appl.if_count) % + ifs[if_idx].pktout_count; - args->thread[i].pktio_dev = args->appl.if_names[if_idx]; + args->thread[i].pktout = + ifs[if_idx].pktout[pktout_idx]; + } tq = odp_queue_create("", NULL); if (tq == ODP_QUEUE_INVALID) { EXAMPLE_ERR("queue_create failed\n"); @@ -890,7 +1095,7 @@ int main(int argc, char *argv[]) odph_odpthreads_join(&thread_tbl[i]); for (i = 0; i < args->appl.if_count; ++i) - odp_pktio_stop(pktio[i]); + odp_pktio_stop(ifs[i].pktio); for (i = 0; i < num_workers; ++i) { odp_timer_cancel(args->thread[i].tim, &ev); @@ -909,8 +1114,8 @@ int main(int argc, char *argv[]) } for (i = 0; i < args->appl.if_count; ++i) - odp_pktio_close(pktio[i]); - free(pktio); + odp_pktio_close(ifs[i].pktio); + free(ifs); free(args->appl.if_names); free(args->appl.if_str); if (0 != odp_pool_destroy(pool)) @@ -951,16 +1156,19 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args) {"dstmac", required_argument, NULL, 'b'}, {"srcip", required_argument, NULL, 's'}, {"dstip", required_argument, NULL, 'd'}, + {"srcport", required_argument, NULL, 'e'}, + {"dstport", required_argument, NULL, 'f'}, {"packetsize", required_argument, NULL, 'p'}, {"mode", required_argument, NULL, 'm'}, {"count", required_argument, NULL, 'n'}, {"timeout", required_argument, NULL, 't'}, {"interval", required_argument, NULL, 'i'}, {"help", no_argument, NULL, 'h'}, + {"udp_tx_burst", required_argument, NULL, 'x'}, {NULL, 0, NULL, 0} }; - static const char *shortopts = "+I:a:b:s:d:p:i:m:n:t:w:c:h"; + static const char *shortopts = "+I:a:b:s:d:p:i:m:n:t:w:c:x:he:f:"; /* let helper collect its own arguments (e.g. --odph_proc) */ odph_parse_options(argc, argv, shortopts, longopts); @@ -970,6 +1178,9 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args) appl_args->payload = 56; appl_args->timeout = -1; appl_args->interval = DEFAULT_PKT_INTERVAL; + appl_args->udp_tx_burst = 16; + appl_args->srcport = 0; + appl_args->dstport = 0; opterr = 0; /* do not issue errors on helper options */ @@ -1076,6 +1287,12 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args) } break; + case 'e': + appl_args->srcport = (unsigned short)atoi(optarg); + break; + case 'f': + appl_args->dstport = (unsigned short)atoi(optarg); + break; case 'p': appl_args->payload = atoi(optarg); break; @@ -1095,6 +1312,14 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args) exit(EXIT_FAILURE); } break; + case 'x': + appl_args->udp_tx_burst = atoi(optarg); + if (appl_args->udp_tx_burst > MAX_UDP_TX_BURST) { + EXAMPLE_ERR("wrong UDP Tx burst size (max %d)\n", + MAX_UDP_TX_BURST); + exit(EXIT_FAILURE); + } + break; case 'h': usage(argv[0]); @@ -1181,6 +1406,8 @@ static void usage(char *progname) "\n" "Optional OPTIONS\n" " -h, --help Display help and exit.\n" + " -e, --srcport src udp port\n" + " -f, --dstport dst udp port\n" " -p, --packetsize payload length of the packets\n" " -t, --timeout only for ping mode, wait ICMP reply timeout seconds\n" " -i, --interval wait interval ms between sending each packet\n" @@ -1189,24 +1416,7 @@ static void usage(char *progname) " default is to assign all\n" " -n, --count the number of packets to be send\n" " -c, --cpumask to set on cores\n" + " -x, --udp_tx_burst size of UDP TX burst\n" "\n", NO_PATH(progname), NO_PATH(progname) ); } -/** - * calc time period - * - *@param recvtime start time - *@param sendtime end time -*/ -static 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; - } -} |