diff options
Diffstat (limited to 'test/common_plat/performance/odp_l2fwd.c')
-rw-r--r-- | test/common_plat/performance/odp_l2fwd.c | 1689 |
1 files changed, 0 insertions, 1689 deletions
diff --git a/test/common_plat/performance/odp_l2fwd.c b/test/common_plat/performance/odp_l2fwd.c deleted file mode 100644 index 25a92cc39..000000000 --- a/test/common_plat/performance/odp_l2fwd.c +++ /dev/null @@ -1,1689 +0,0 @@ -/* Copyright (c) 2014, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/** - * @file - * - * @example odp_l2fwd.c ODP basic forwarding application - */ - -/** enable strtok */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include <stdlib.h> -#include <getopt.h> -#include <unistd.h> -#include <errno.h> -#include <inttypes.h> -#include <assert.h> -#include <signal.h> - -#include <test_debug.h> - -#include <odp_api.h> -#include <odp/helper/odph_api.h> - -/** @def MAX_WORKERS - * @brief Maximum number of worker threads - */ -#define MAX_WORKERS 32 - -/** @def SHM_PKT_POOL_SIZE - * @brief Size of the shared memory block - */ -#define SHM_PKT_POOL_SIZE 8192 - -/** @def SHM_PKT_POOL_BUF_SIZE - * @brief Buffer size of the packet pool buffer - */ -#define SHM_PKT_POOL_BUF_SIZE 1856 - -/** @def MAX_PKT_BURST - * @brief Maximum number of packet in a burst - */ -#define MAX_PKT_BURST 32 - -/** Maximum number of pktio queues per interface */ -#define MAX_QUEUES 32 - -/** Maximum number of pktio interfaces */ -#define MAX_PKTIOS 8 - -/** Maximum pktio index table size */ -#define MAX_PKTIO_INDEXES 1024 - -/** - * Packet input mode - */ -typedef enum pktin_mode_t { - DIRECT_RECV, - PLAIN_QUEUE, - SCHED_PARALLEL, - SCHED_ATOMIC, - SCHED_ORDERED, -} pktin_mode_t; - -/** - * Packet output modes - */ -typedef enum pktout_mode_t { - PKTOUT_DIRECT, - PKTOUT_QUEUE -} pktout_mode_t; - -static inline int sched_mode(pktin_mode_t in_mode) -{ - return (in_mode == SCHED_PARALLEL) || - (in_mode == SCHED_ATOMIC) || - (in_mode == SCHED_ORDERED); -} - -/** 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 cpu_count; - int if_count; /**< Number of interfaces to be used */ - int addr_count; /**< Number of dst addresses to be used */ - int num_workers; /**< Number of worker threads */ - char **if_names; /**< Array of pointers to interface names */ - odph_ethaddr_t addrs[MAX_PKTIOS]; /**< Array of dst addresses */ - pktin_mode_t in_mode; /**< Packet input mode */ - pktout_mode_t out_mode; /**< Packet output mode */ - int time; /**< Time in seconds to run. */ - int accuracy; /**< Number of seconds to get and print statistics */ - char *if_str; /**< Storage for interface names */ - int dst_change; /**< Change destination eth addresses */ - int src_change; /**< Change source eth addresses */ - int error_check; /**< Check packet errors */ - int sched_mode; /**< Scheduler mode */ - int num_groups; /**< Number of scheduling groups */ -} appl_args_t; - -static int exit_threads; /**< Break workers loop if set to 1 */ - -static void sig_handler(int signo ODP_UNUSED) -{ - exit_threads = 1; -} - -/** - * Statistics - */ -typedef union { - struct { - /** Number of forwarded packets */ - uint64_t packets; - /** Packets dropped due to receive error */ - uint64_t rx_drops; - /** Packets dropped due to transmit error */ - uint64_t tx_drops; - } s; - - uint8_t padding[ODP_CACHE_LINE_SIZE]; -} stats_t ODP_ALIGNED_CACHE; - -/** - * Thread specific arguments - */ -typedef struct thread_args_t { - int thr_idx; - int num_pktio; - int num_groups; - - struct { - odp_pktin_queue_t pktin; - odp_pktout_queue_t pktout; - odp_queue_t rx_queue; - odp_queue_t tx_queue; - int rx_idx; - int tx_idx; - int rx_queue_idx; - int tx_queue_idx; - } pktio[MAX_PKTIOS]; - - /* Groups to join */ - odp_schedule_group_t group[MAX_PKTIOS]; - - /* Pointer to per thread stats */ - stats_t *stats; - -} thread_args_t; - -/** - * Grouping of all global data - */ -typedef struct { - /** Barriers to synchronize main and workers */ - odp_barrier_t init_barrier; - odp_barrier_t term_barrier; - /** Per thread packet stats */ - stats_t stats[MAX_WORKERS]; - /** Application (parsed) arguments */ - appl_args_t appl; - /** Thread specific arguments */ - thread_args_t thread[MAX_WORKERS]; - /** Table of port ethernet addresses */ - odph_ethaddr_t port_eth_addr[MAX_PKTIOS]; - /** Table of dst ethernet addresses */ - odph_ethaddr_t dst_eth_addr[MAX_PKTIOS]; - /** Table of dst ports. This is used by non-sched modes. */ - int dst_port[MAX_PKTIOS]; - /** Table of pktio handles */ - struct { - odp_pktio_t pktio; - odp_pktin_queue_t pktin[MAX_QUEUES]; - odp_pktout_queue_t pktout[MAX_QUEUES]; - odp_queue_t rx_q[MAX_QUEUES]; - odp_queue_t tx_q[MAX_QUEUES]; - int num_rx_thr; - int num_tx_thr; - int num_rx_queue; - int num_tx_queue; - int next_rx_queue; - int next_tx_queue; - } pktios[MAX_PKTIOS]; - - /** Destination port lookup table. - * Table index is pktio_index of the API. This is used by the sched - * mode. */ - uint8_t dst_port_from_idx[MAX_PKTIO_INDEXES]; - -} args_t; - -/** Global pointer to args */ -static args_t *gbl_args; - -/** - * 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 packets - * @param num Number of packets in pkt_tbl[] - * - * @return Number of packets dropped - */ -static inline int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned num) -{ - odp_packet_t pkt; - unsigned dropped = 0; - unsigned i, j; - - for (i = 0, j = 0; i < num; ++i) { - pkt = pkt_tbl[i]; - - if (odp_unlikely(odp_packet_has_error(pkt))) { - odp_packet_free(pkt); /* Drop */ - dropped++; - } else if (odp_unlikely(i != j++)) { - pkt_tbl[j - 1] = pkt; - } - } - - return dropped; -} - -/** - * Fill packets' eth addresses according to the destination port - * - * @param pkt_tbl Array of packets - * @param num Number of packets in the array - * @param dst_port Destination port - */ -static inline void fill_eth_addrs(odp_packet_t pkt_tbl[], - unsigned num, int dst_port) -{ - odp_packet_t pkt; - odph_ethhdr_t *eth; - unsigned i; - - if (!gbl_args->appl.dst_change && !gbl_args->appl.src_change) - return; - - for (i = 0; i < num; ++i) { - pkt = pkt_tbl[i]; - - odp_packet_prefetch(pkt, 0, ODPH_ETHHDR_LEN); - - eth = odp_packet_data(pkt); - - if (gbl_args->appl.src_change) - eth->src = gbl_args->port_eth_addr[dst_port]; - - if (gbl_args->appl.dst_change) - eth->dst = gbl_args->dst_eth_addr[dst_port]; - } -} - -static inline int event_queue_send(odp_queue_t queue, odp_packet_t *pkt_tbl, - unsigned pkts) -{ - int ret; - unsigned i; - unsigned sent = 0; - odp_event_t ev_tbl[pkts]; - - for (i = 0; i < pkts; i++) - ev_tbl[i] = odp_packet_to_event(pkt_tbl[i]); - - while (sent < pkts) { - ret = odp_queue_enq_multi(queue, &ev_tbl[sent], pkts - sent); - - if (ret < 0) { - LOG_ERR("Failed to send packet as events\n"); - break; - } - - sent += ret; - } - - return sent; -} - -/** - * Packet IO worker thread using scheduled queues - * - * @param arg thread arguments of type 'thread_args_t *' - */ -static int run_worker_sched_mode(void *arg) -{ - int pkts; - int thr; - int dst_idx; - int i; - int pktio, num_pktio; - odp_pktout_queue_t pktout[MAX_PKTIOS]; - odp_queue_t tx_queue[MAX_PKTIOS]; - thread_args_t *thr_args = arg; - stats_t *stats = thr_args->stats; - int use_event_queue = gbl_args->appl.out_mode; - pktin_mode_t in_mode = gbl_args->appl.in_mode; - - thr = odp_thread_id(); - - if (gbl_args->appl.num_groups) { - odp_thrmask_t mask; - - odp_thrmask_zero(&mask); - odp_thrmask_set(&mask, thr); - - /* Join non-default groups */ - for (i = 0; i < thr_args->num_groups; i++) { - if (odp_schedule_group_join(thr_args->group[i], - &mask)) { - LOG_ERR("Join failed\n"); - return -1; - } - } - } - - num_pktio = thr_args->num_pktio; - - if (num_pktio > MAX_PKTIOS) { - LOG_ERR("Too many pktios %i\n", num_pktio); - return -1; - } - - for (pktio = 0; pktio < num_pktio; pktio++) { - tx_queue[pktio] = thr_args->pktio[pktio].tx_queue; - pktout[pktio] = thr_args->pktio[pktio].pktout; - } - - printf("[%02i] PKTIN_SCHED_%s, %s\n", thr, - (in_mode == SCHED_PARALLEL) ? "PARALLEL" : - ((in_mode == SCHED_ATOMIC) ? "ATOMIC" : "ORDERED"), - (use_event_queue) ? "PKTOUT_QUEUE" : "PKTOUT_DIRECT"); - - odp_barrier_wait(&gbl_args->init_barrier); - - /* Loop packets */ - while (!exit_threads) { - odp_event_t ev_tbl[MAX_PKT_BURST]; - odp_packet_t pkt_tbl[MAX_PKT_BURST]; - int sent; - unsigned tx_drops; - int src_idx; - - pkts = odp_schedule_multi(NULL, ODP_SCHED_NO_WAIT, ev_tbl, - MAX_PKT_BURST); - - if (pkts <= 0) - continue; - - for (i = 0; i < pkts; i++) - pkt_tbl[i] = odp_packet_from_event(ev_tbl[i]); - - if (gbl_args->appl.error_check) { - int rx_drops; - - /* Drop packets with errors */ - rx_drops = drop_err_pkts(pkt_tbl, pkts); - - if (odp_unlikely(rx_drops)) { - stats->s.rx_drops += rx_drops; - if (pkts == rx_drops) - continue; - - pkts -= rx_drops; - } - } - - /* packets from the same queue are from the same interface */ - src_idx = odp_packet_input_index(pkt_tbl[0]); - assert(src_idx >= 0); - dst_idx = gbl_args->dst_port_from_idx[src_idx]; - fill_eth_addrs(pkt_tbl, pkts, dst_idx); - - if (odp_unlikely(use_event_queue)) - sent = event_queue_send(tx_queue[dst_idx], pkt_tbl, - pkts); - else - sent = odp_pktout_send(pktout[dst_idx], pkt_tbl, pkts); - - sent = odp_unlikely(sent < 0) ? 0 : sent; - tx_drops = pkts - sent; - - if (odp_unlikely(tx_drops)) { - stats->s.tx_drops += tx_drops; - - /* Drop rejected packets */ - for (i = sent; i < pkts; i++) - odp_packet_free(pkt_tbl[i]); - } - - stats->s.packets += pkts; - } - - /* Make sure that latest stat writes are visible to other threads */ - odp_mb_full(); - - /* Wait until pktio devices are stopped */ - odp_barrier_wait(&gbl_args->term_barrier); - - /* Free remaining events in queues */ - while (1) { - odp_event_t ev; - - ev = odp_schedule(NULL, - odp_schedule_wait_time(ODP_TIME_SEC_IN_NS)); - - if (ev == ODP_EVENT_INVALID) - break; - - odp_event_free(ev); - } - - return 0; -} - -/** - * Packet IO worker thread using plain queues - * - * @param arg thread arguments of type 'thread_args_t *' - */ -static int run_worker_plain_queue_mode(void *arg) -{ - int thr; - int pkts; - odp_packet_t pkt_tbl[MAX_PKT_BURST]; - int dst_idx, num_pktio; - odp_queue_t queue; - odp_pktout_queue_t pktout; - odp_queue_t tx_queue; - int pktio = 0; - thread_args_t *thr_args = arg; - stats_t *stats = thr_args->stats; - int use_event_queue = gbl_args->appl.out_mode; - int i; - - thr = odp_thread_id(); - - num_pktio = thr_args->num_pktio; - dst_idx = thr_args->pktio[pktio].tx_idx; - queue = thr_args->pktio[pktio].rx_queue; - pktout = thr_args->pktio[pktio].pktout; - tx_queue = thr_args->pktio[pktio].tx_queue; - - printf("[%02i] num pktios %i, PKTIN_QUEUE, %s\n", thr, num_pktio, - (use_event_queue) ? "PKTOUT_QUEUE" : "PKTOUT_DIRECT"); - - odp_barrier_wait(&gbl_args->init_barrier); - - /* Loop packets */ - while (!exit_threads) { - int sent; - unsigned tx_drops; - odp_event_t event[MAX_PKT_BURST]; - - if (num_pktio > 1) { - dst_idx = thr_args->pktio[pktio].tx_idx; - queue = thr_args->pktio[pktio].rx_queue; - pktout = thr_args->pktio[pktio].pktout; - if (odp_unlikely(use_event_queue)) - tx_queue = thr_args->pktio[pktio].tx_queue; - - pktio++; - if (pktio == num_pktio) - pktio = 0; - } - - pkts = odp_queue_deq_multi(queue, event, MAX_PKT_BURST); - if (odp_unlikely(pkts <= 0)) - continue; - - for (i = 0; i < pkts; i++) - pkt_tbl[i] = odp_packet_from_event(event[i]); - - if (gbl_args->appl.error_check) { - int rx_drops; - - /* Drop packets with errors */ - rx_drops = drop_err_pkts(pkt_tbl, pkts); - - if (odp_unlikely(rx_drops)) { - stats->s.rx_drops += rx_drops; - if (pkts == rx_drops) - continue; - - pkts -= rx_drops; - } - } - - fill_eth_addrs(pkt_tbl, pkts, dst_idx); - - if (odp_unlikely(use_event_queue)) - sent = event_queue_send(tx_queue, pkt_tbl, pkts); - else - sent = odp_pktout_send(pktout, pkt_tbl, pkts); - - sent = odp_unlikely(sent < 0) ? 0 : sent; - tx_drops = pkts - sent; - - if (odp_unlikely(tx_drops)) { - int i; - - stats->s.tx_drops += tx_drops; - - /* Drop rejected packets */ - for (i = sent; i < pkts; i++) - odp_packet_free(pkt_tbl[i]); - } - - stats->s.packets += pkts; - } - - /* Make sure that latest stat writes are visible to other threads */ - odp_mb_full(); - - /* Wait until pktio devices are stopped */ - odp_barrier_wait(&gbl_args->term_barrier); - - /* Free remaining events in queues */ - for (i = 0; i < num_pktio; i++) { - odp_time_t recv_last = odp_time_local(); - odp_time_t since_last; - - queue = thr_args->pktio[i].rx_queue; - do { - odp_event_t ev = odp_queue_deq(queue); - - if (ev != ODP_EVENT_INVALID) { - recv_last = odp_time_local(); - odp_event_free(ev); - } - - since_last = odp_time_diff(odp_time_local(), recv_last); - } while (odp_time_to_ns(since_last) < ODP_TIME_SEC_IN_NS); - } - - return 0; -} - -/** - * Packet IO worker thread accessing IO resources directly - * - * @param arg thread arguments of type 'thread_args_t *' - */ -static int run_worker_direct_mode(void *arg) -{ - int thr; - int pkts; - odp_packet_t pkt_tbl[MAX_PKT_BURST]; - int dst_idx, num_pktio; - odp_pktin_queue_t pktin; - odp_pktout_queue_t pktout; - odp_queue_t tx_queue; - int pktio = 0; - thread_args_t *thr_args = arg; - stats_t *stats = thr_args->stats; - int use_event_queue = gbl_args->appl.out_mode; - - thr = odp_thread_id(); - - num_pktio = thr_args->num_pktio; - dst_idx = thr_args->pktio[pktio].tx_idx; - pktin = thr_args->pktio[pktio].pktin; - pktout = thr_args->pktio[pktio].pktout; - tx_queue = thr_args->pktio[pktio].tx_queue; - - printf("[%02i] num pktios %i, PKTIN_DIRECT, %s\n", thr, num_pktio, - (use_event_queue) ? "PKTOUT_QUEUE" : "PKTOUT_DIRECT"); - - odp_barrier_wait(&gbl_args->init_barrier); - - /* Loop packets */ - while (!exit_threads) { - int sent; - unsigned tx_drops; - - if (num_pktio > 1) { - dst_idx = thr_args->pktio[pktio].tx_idx; - pktin = thr_args->pktio[pktio].pktin; - pktout = thr_args->pktio[pktio].pktout; - if (odp_unlikely(use_event_queue)) - tx_queue = thr_args->pktio[pktio].tx_queue; - - pktio++; - if (pktio == num_pktio) - pktio = 0; - } - - pkts = odp_pktin_recv(pktin, pkt_tbl, MAX_PKT_BURST); - if (odp_unlikely(pkts <= 0)) - continue; - - if (gbl_args->appl.error_check) { - int rx_drops; - - /* Drop packets with errors */ - rx_drops = drop_err_pkts(pkt_tbl, pkts); - - if (odp_unlikely(rx_drops)) { - stats->s.rx_drops += rx_drops; - if (pkts == rx_drops) - continue; - - pkts -= rx_drops; - } - } - - fill_eth_addrs(pkt_tbl, pkts, dst_idx); - - if (odp_unlikely(use_event_queue)) - sent = event_queue_send(tx_queue, pkt_tbl, pkts); - else - sent = odp_pktout_send(pktout, pkt_tbl, pkts); - - sent = odp_unlikely(sent < 0) ? 0 : sent; - tx_drops = pkts - sent; - - if (odp_unlikely(tx_drops)) { - int i; - - stats->s.tx_drops += tx_drops; - - /* Drop rejected packets */ - for (i = sent; i < pkts; i++) - odp_packet_free(pkt_tbl[i]); - } - - stats->s.packets += pkts; - } - - /* Make sure that latest stat writes are visible to other threads */ - odp_mb_full(); - - return 0; -} - -/** - * Create a pktio handle, optionally associating a default input queue. - * - * @param dev Name of device to open - * @param index Pktio index - * @param pool Pool to associate with device for packet RX/TX - * - * @retval 0 on success - * @retval -1 on failure - */ -static int create_pktio(const char *dev, int idx, int num_rx, int num_tx, - odp_pool_t pool, odp_schedule_group_t group) -{ - odp_pktio_t pktio; - odp_pktio_param_t pktio_param; - odp_schedule_sync_t sync_mode; - odp_pktio_capability_t capa; - odp_pktio_config_t config; - odp_pktin_queue_param_t pktin_param; - odp_pktout_queue_param_t pktout_param; - odp_pktio_op_mode_t mode_rx; - odp_pktio_op_mode_t mode_tx; - pktin_mode_t in_mode = gbl_args->appl.in_mode; - odp_pktio_info_t info; - - odp_pktio_param_init(&pktio_param); - - if (in_mode == PLAIN_QUEUE) - pktio_param.in_mode = ODP_PKTIN_MODE_QUEUE; - else if (in_mode != DIRECT_RECV) /* pktin_mode SCHED_* */ - pktio_param.in_mode = ODP_PKTIN_MODE_SCHED; - - if (gbl_args->appl.out_mode != PKTOUT_DIRECT) - pktio_param.out_mode = ODP_PKTOUT_MODE_QUEUE; - - pktio = odp_pktio_open(dev, pool, &pktio_param); - if (pktio == ODP_PKTIO_INVALID) { - LOG_ERR("Error: failed to open %s\n", dev); - return -1; - } - - if (odp_pktio_info(pktio, &info)) { - LOG_ERR("Error: pktio info failed %s\n", dev); - return -1; - } - - printf("created pktio %" PRIu64 ", dev: %s, drv: %s\n", - odp_pktio_to_u64(pktio), dev, info.drv_name); - - if (odp_pktio_capability(pktio, &capa)) { - LOG_ERR("Error: capability query failed %s\n", dev); - return -1; - } - - odp_pktio_config_init(&config); - config.parser.layer = gbl_args->appl.error_check ? - ODP_PKTIO_PARSER_LAYER_ALL : - ODP_PKTIO_PARSER_LAYER_NONE; - odp_pktio_config(pktio, &config); - - odp_pktin_queue_param_init(&pktin_param); - odp_pktout_queue_param_init(&pktout_param); - - /* By default use a queue per worker. Sched mode ignores rx side - * setting. */ - mode_rx = ODP_PKTIO_OP_MT_UNSAFE; - mode_tx = ODP_PKTIO_OP_MT_UNSAFE; - - if (gbl_args->appl.sched_mode) { - if (gbl_args->appl.in_mode == SCHED_ATOMIC) - sync_mode = ODP_SCHED_SYNC_ATOMIC; - else if (gbl_args->appl.in_mode == SCHED_ORDERED) - sync_mode = ODP_SCHED_SYNC_ORDERED; - else - sync_mode = ODP_SCHED_SYNC_PARALLEL; - - pktin_param.queue_param.sched.prio = ODP_SCHED_PRIO_DEFAULT; - pktin_param.queue_param.sched.sync = sync_mode; - pktin_param.queue_param.sched.group = group; - } - - if (num_rx > (int)capa.max_input_queues) { - printf("Sharing %i input queues between %i workers\n", - capa.max_input_queues, num_rx); - num_rx = capa.max_input_queues; - mode_rx = ODP_PKTIO_OP_MT; - } - - if (num_tx > (int)capa.max_output_queues) { - printf("Sharing %i output queues between %i workers\n", - capa.max_output_queues, num_tx); - num_tx = capa.max_output_queues; - mode_tx = ODP_PKTIO_OP_MT; - } - - pktin_param.hash_enable = 1; - pktin_param.hash_proto.proto.ipv4_udp = 1; - pktin_param.num_queues = num_rx; - pktin_param.op_mode = mode_rx; - - pktout_param.op_mode = mode_tx; - pktout_param.num_queues = num_tx; - - if (odp_pktin_queue_config(pktio, &pktin_param)) { - LOG_ERR("Error: input queue config failed %s\n", dev); - return -1; - } - - if (odp_pktout_queue_config(pktio, &pktout_param)) { - LOG_ERR("Error: output queue config failed %s\n", dev); - return -1; - } - - if (gbl_args->appl.in_mode == DIRECT_RECV) { - if (odp_pktin_queue(pktio, gbl_args->pktios[idx].pktin, - num_rx) != num_rx) { - LOG_ERR("Error: pktin queue query failed %s\n", - dev); - return -1; - } - } else { - if (odp_pktin_event_queue(pktio, - gbl_args->pktios[idx].rx_q, - num_rx) != num_rx) { - LOG_ERR("Error: pktin event queue query failed %s\n", - dev); - return -1; - } - } - - if (gbl_args->appl.out_mode == PKTOUT_DIRECT) { - if (odp_pktout_queue(pktio, - gbl_args->pktios[idx].pktout, - num_tx) != num_tx) { - LOG_ERR("Error: pktout queue query failed %s\n", dev); - return -1; - } - } else { - if (odp_pktout_event_queue(pktio, - gbl_args->pktios[idx].tx_q, - num_tx) != num_tx) { - LOG_ERR("Error: event queue query failed %s\n", dev); - return -1; - } - } - - printf("created %i input and %i output queues on (%s)\n", - num_rx, num_tx, dev); - - gbl_args->pktios[idx].num_rx_queue = num_rx; - gbl_args->pktios[idx].num_tx_queue = num_tx; - gbl_args->pktios[idx].pktio = pktio; - - return 0; -} - -/** - * Print statistics - * - * @param num_workers Number of worker threads - * @param thr_stats Pointer to stats storage - * @param duration Number of seconds to loop in - * @param timeout Number of seconds for stats calculation - * - */ -static int print_speed_stats(int num_workers, stats_t *thr_stats, - int duration, int timeout) -{ - uint64_t pkts = 0; - uint64_t pkts_prev = 0; - uint64_t pps; - uint64_t rx_drops, tx_drops; - uint64_t maximum_pps = 0; - int i; - int elapsed = 0; - int stats_enabled = 1; - int loop_forever = (duration == 0); - - if (timeout <= 0) { - stats_enabled = 0; - timeout = 1; - } - /* Wait for all threads to be ready*/ - odp_barrier_wait(&gbl_args->init_barrier); - - do { - pkts = 0; - rx_drops = 0; - tx_drops = 0; - - sleep(timeout); - - for (i = 0; i < num_workers; i++) { - pkts += thr_stats[i].s.packets; - rx_drops += thr_stats[i].s.rx_drops; - tx_drops += thr_stats[i].s.tx_drops; - } - if (stats_enabled) { - pps = (pkts - pkts_prev) / timeout; - if (pps > maximum_pps) - maximum_pps = pps; - printf("%" PRIu64 " pps, %" PRIu64 " max pps, ", pps, - maximum_pps); - - printf(" %" PRIu64 " rx drops, %" PRIu64 " tx drops\n", - rx_drops, tx_drops); - - pkts_prev = pkts; - } - elapsed += timeout; - } while (!exit_threads && (loop_forever || (elapsed < duration))); - - if (stats_enabled) - printf("TEST RESULT: %" PRIu64 " maximum packets per second.\n", - maximum_pps); - - return pkts > 100 ? 0 : -1; -} - -static void print_port_mapping(void) -{ - int if_count; - int pktio; - - if_count = gbl_args->appl.if_count; - - printf("\nPort config\n--------------------\n"); - - for (pktio = 0; pktio < if_count; pktio++) { - const char *dev = gbl_args->appl.if_names[pktio]; - - printf("Port %i (%s)\n", pktio, dev); - printf(" rx workers %i\n", - gbl_args->pktios[pktio].num_rx_thr); - printf(" tx workers %i\n", - gbl_args->pktios[pktio].num_tx_thr); - printf(" rx queues %i\n", - gbl_args->pktios[pktio].num_rx_queue); - printf(" tx queues %i\n", - gbl_args->pktios[pktio].num_tx_queue); - } - - printf("\n"); -} - -/** - * Find the destination port for a given input port - * - * @param port Input port index - */ -static int find_dest_port(int port) -{ - /* Even number of ports */ - if (gbl_args->appl.if_count % 2 == 0) - return (port % 2 == 0) ? port + 1 : port - 1; - - /* Odd number of ports */ - if (port == gbl_args->appl.if_count - 1) - return 0; - else - return port + 1; -} - -/* - * Bind worker threads to interfaces and calculate number of queues needed - * - * less workers (N) than interfaces (M) - * - assign each worker to process every Nth interface - * - workers process inequal number of interfaces, when M is not divisible by N - * - needs only single queue per interface - * otherwise - * - assign an interface to every Mth worker - * - interfaces are processed by inequal number of workers, when N is not - * divisible by M - * - tries to configure a queue per worker per interface - * - shares queues, if interface capability does not allows a queue per worker - */ -static void bind_workers(void) -{ - int if_count, num_workers; - int rx_idx, tx_idx, thr, pktio, i; - thread_args_t *thr_args; - - if_count = gbl_args->appl.if_count; - num_workers = gbl_args->appl.num_workers; - - if (gbl_args->appl.sched_mode) { - /* all threads receive and send on all pktios */ - for (i = 0; i < if_count; i++) { - gbl_args->pktios[i].num_rx_thr = num_workers; - gbl_args->pktios[i].num_tx_thr = num_workers; - } - - for (thr = 0; thr < num_workers; thr++) { - thr_args = &gbl_args->thread[thr]; - thr_args->num_pktio = if_count; - - /* In sched mode, pktios are not cross connected with - * local pktio indexes */ - for (i = 0; i < if_count; i++) { - thr_args->pktio[i].rx_idx = i; - thr_args->pktio[i].tx_idx = i; - } - } - } else { - /* initialize port forwarding table */ - for (rx_idx = 0; rx_idx < if_count; rx_idx++) - gbl_args->dst_port[rx_idx] = find_dest_port(rx_idx); - - if (if_count > num_workers) { - /* Less workers than pktios. Assign single worker per - * pktio. */ - thr = 0; - - for (rx_idx = 0; rx_idx < if_count; rx_idx++) { - thr_args = &gbl_args->thread[thr]; - pktio = thr_args->num_pktio; - /* Cross connect rx to tx */ - tx_idx = gbl_args->dst_port[rx_idx]; - thr_args->pktio[pktio].rx_idx = rx_idx; - thr_args->pktio[pktio].tx_idx = tx_idx; - thr_args->num_pktio++; - - gbl_args->pktios[rx_idx].num_rx_thr++; - gbl_args->pktios[tx_idx].num_tx_thr++; - - thr++; - if (thr >= num_workers) - thr = 0; - } - } else { - /* More workers than pktios. Assign at least one worker - * per pktio. */ - rx_idx = 0; - - for (thr = 0; thr < num_workers; thr++) { - thr_args = &gbl_args->thread[thr]; - pktio = thr_args->num_pktio; - /* Cross connect rx to tx */ - tx_idx = gbl_args->dst_port[rx_idx]; - thr_args->pktio[pktio].rx_idx = rx_idx; - thr_args->pktio[pktio].tx_idx = tx_idx; - thr_args->num_pktio++; - - gbl_args->pktios[rx_idx].num_rx_thr++; - gbl_args->pktios[tx_idx].num_tx_thr++; - - rx_idx++; - if (rx_idx >= if_count) - rx_idx = 0; - } - } - } -} - -/* - * Bind queues to threads and fill in missing thread arguments (handles) - */ -static void bind_queues(void) -{ - int num_workers; - int thr, i; - - num_workers = gbl_args->appl.num_workers; - - printf("\nQueue binding (indexes)\n-----------------------\n"); - - for (thr = 0; thr < num_workers; thr++) { - int rx_idx, tx_idx; - thread_args_t *thr_args = &gbl_args->thread[thr]; - int num = thr_args->num_pktio; - - printf("worker %i\n", thr); - - for (i = 0; i < num; i++) { - int rx_queue, tx_queue; - - rx_idx = thr_args->pktio[i].rx_idx; - tx_idx = thr_args->pktio[i].tx_idx; - rx_queue = gbl_args->pktios[rx_idx].next_rx_queue; - tx_queue = gbl_args->pktios[tx_idx].next_tx_queue; - - thr_args->pktio[i].rx_queue_idx = rx_queue; - thr_args->pktio[i].tx_queue_idx = tx_queue; - thr_args->pktio[i].pktin = - gbl_args->pktios[rx_idx].pktin[rx_queue]; - thr_args->pktio[i].rx_queue = - gbl_args->pktios[rx_idx].rx_q[rx_queue]; - thr_args->pktio[i].pktout = - gbl_args->pktios[tx_idx].pktout[tx_queue]; - thr_args->pktio[i].tx_queue = - gbl_args->pktios[tx_idx].tx_q[tx_queue]; - - if (!gbl_args->appl.sched_mode) - printf(" rx: pktio %i, queue %i\n", - rx_idx, rx_queue); - - printf(" tx: pktio %i, queue %i\n", - tx_idx, tx_queue); - - rx_queue++; - tx_queue++; - - if (rx_queue >= gbl_args->pktios[rx_idx].num_rx_queue) - rx_queue = 0; - if (tx_queue >= gbl_args->pktios[tx_idx].num_tx_queue) - tx_queue = 0; - - gbl_args->pktios[rx_idx].next_rx_queue = rx_queue; - gbl_args->pktios[tx_idx].next_tx_queue = tx_queue; - } - } - - printf("\n"); -} - -static void init_port_lookup_tbl(void) -{ - int rx_idx, if_count; - - if_count = gbl_args->appl.if_count; - - for (rx_idx = 0; rx_idx < if_count; rx_idx++) { - odp_pktio_t pktio = gbl_args->pktios[rx_idx].pktio; - int pktio_idx = odp_pktio_index(pktio); - int dst_port = find_dest_port(rx_idx); - - if (pktio_idx < 0 || pktio_idx >= MAX_PKTIO_INDEXES) { - LOG_ERR("Bad pktio index %i\n", pktio_idx); - exit(EXIT_FAILURE); - } - - gbl_args->dst_port_from_idx[pktio_idx] = dst_port; - } -} - -/** - * Prinf usage information - */ -static void usage(char *progname) -{ - printf("\n" - "OpenDataPlane L2 forwarding application.\n" - "\n" - "Usage: %s [options]\n" - "\n" - " E.g. %s -i eth0,eth1,eth2,eth3 -m 0 -t 1\n" - " In the above example,\n" - " eth0 will send pkts to eth1 and vice versa\n" - " eth2 will send pkts to eth3 and vice versa\n" - "\n" - "Mandatory OPTIONS:\n" - " -i, --interface <name> Eth interfaces (comma-separated, no spaces)\n" - " Interface count min 1, max %i\n" - "\n" - "Optional OPTIONS:\n" - " -m, --mode <arg> Packet input mode\n" - " 0: Direct mode: PKTIN_MODE_DIRECT (default)\n" - " 1: Scheduler mode with parallel queues:\n" - " PKTIN_MODE_SCHED + SCHED_SYNC_PARALLEL\n" - " 2: Scheduler mode with atomic queues:\n" - " PKTIN_MODE_SCHED + SCHED_SYNC_ATOMIC\n" - " 3: Scheduler mode with ordered queues:\n" - " PKTIN_MODE_SCHED + SCHED_SYNC_ORDERED\n" - " 4: Plain queue mode: PKTIN_MODE_QUEUE\n" - " -o, --out_mode <arg> Packet output mode\n" - " 0: Direct mode: PKTOUT_MODE_DIRECT (default)\n" - " 1: Queue mode: PKTOUT_MODE_QUEUE\n" - " -c, --count <num> CPU count.\n" - " -t, --time <sec> Time in seconds to run.\n" - " -a, --accuracy <sec> Time in seconds get print statistics\n" - " (default is 1 second).\n" - " -d, --dst_change <arg> 0: Don't change packets' dst eth addresses\n" - " 1: Change packets' dst eth addresses (default)\n" - " -s, --src_change <arg> 0: Don't change packets' src eth addresses\n" - " 1: Change packets' src eth addresses (default)\n" - " -r, --dst_addr <addr> Destination addresses (comma-separated, no spaces)\n" - " Requires also the -d flag to be set\n" - " -e, --error_check <arg> 0: Don't check packet errors (default)\n" - " 1: Check packet errors\n" - " -g, --groups <num> Number of groups to use: 0 ... num\n" - " 0: SCHED_GROUP_ALL (default)\n" - " num: must not exceed number of interfaces or workers\n" - " -h, --help Display help and exit.\n\n" - "\n", NO_PATH(progname), NO_PATH(progname), MAX_PKTIOS - ); -} - -/** - * Parse and store the command line arguments - * - * @param argc argument count - * @param argv[] argument vector - * @param appl_args Store application arguments here - */ -static void parse_args(int argc, char *argv[], appl_args_t *appl_args) -{ - int opt; - int long_index; - char *token; - char *addr_str; - size_t len; - int i; - static const struct option longopts[] = { - {"count", required_argument, NULL, 'c'}, - {"time", required_argument, NULL, 't'}, - {"accuracy", required_argument, NULL, 'a'}, - {"interface", required_argument, NULL, 'i'}, - {"mode", required_argument, NULL, 'm'}, - {"out_mode", required_argument, NULL, 'o'}, - {"dst_addr", required_argument, NULL, 'r'}, - {"dst_change", required_argument, NULL, 'd'}, - {"src_change", required_argument, NULL, 's'}, - {"error_check", required_argument, NULL, 'e'}, - {"groups", required_argument, NULL, 'g'}, - {"help", no_argument, NULL, 'h'}, - {NULL, 0, NULL, 0} - }; - - static const char *shortopts = "+c:+t:+a:i:m:o:r:d:s:e:g:h"; - - /* let helper collect its own arguments (e.g. --odph_proc) */ - odph_parse_options(argc, argv, shortopts, longopts); - - appl_args->time = 0; /* loop forever if time to run is 0 */ - appl_args->accuracy = 1; /* get and print pps stats second */ - appl_args->dst_change = 1; /* change eth dst address by default */ - appl_args->src_change = 1; /* change eth src address by default */ - appl_args->num_groups = 0; /* use default group */ - appl_args->error_check = 0; /* don't check packet errors by default */ - - opterr = 0; /* do not issue errors on helper options */ - - while (1) { - opt = getopt_long(argc, argv, shortopts, longopts, &long_index); - - if (opt == -1) - break; /* No more options */ - - switch (opt) { - case 'c': - appl_args->cpu_count = atoi(optarg); - break; - case 't': - appl_args->time = atoi(optarg); - break; - case 'a': - appl_args->accuracy = atoi(optarg); - break; - /* parse packet-io interface names */ - case 'r': - len = strlen(optarg); - if (len == 0) { - usage(argv[0]); - exit(EXIT_FAILURE); - } - len += 1; /* add room for '\0' */ - - addr_str = malloc(len); - if (addr_str == NULL) { - usage(argv[0]); - exit(EXIT_FAILURE); - } - - /* store the mac addresses names */ - strcpy(addr_str, optarg); - for (token = strtok(addr_str, ","), i = 0; - token != NULL; token = strtok(NULL, ","), i++) { - if (i >= MAX_PKTIOS) { - printf("too many MAC addresses\n"); - usage(argv[0]); - exit(EXIT_FAILURE); - } - if (odph_eth_addr_parse(&appl_args->addrs[i], - token) != 0) { - printf("invalid MAC address\n"); - usage(argv[0]); - exit(EXIT_FAILURE); - } - } - appl_args->addr_count = i; - if (appl_args->addr_count < 1) { - usage(argv[0]); - exit(EXIT_FAILURE); - } - free(addr_str); - break; - case 'i': - len = strlen(optarg); - if (len == 0) { - usage(argv[0]); - exit(EXIT_FAILURE); - } - len += 1; /* add room for '\0' */ - - appl_args->if_str = malloc(len); - if (appl_args->if_str == NULL) { - usage(argv[0]); - exit(EXIT_FAILURE); - } - - /* count the number of tokens separated by ',' */ - strcpy(appl_args->if_str, optarg); - for (token = strtok(appl_args->if_str, ","), i = 0; - token != NULL; - token = strtok(NULL, ","), i++) - ; - - appl_args->if_count = i; - - if (appl_args->if_count < 1 || - appl_args->if_count > MAX_PKTIOS) { - 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(appl_args->if_str, optarg); - for (token = strtok(appl_args->if_str, ","), i = 0; - token != NULL; token = strtok(NULL, ","), i++) { - appl_args->if_names[i] = token; - } - break; - case 'm': - i = atoi(optarg); - if (i == 1) - appl_args->in_mode = SCHED_PARALLEL; - else if (i == 2) - appl_args->in_mode = SCHED_ATOMIC; - else if (i == 3) - appl_args->in_mode = SCHED_ORDERED; - else if (i == 4) - appl_args->in_mode = PLAIN_QUEUE; - else - appl_args->in_mode = DIRECT_RECV; - break; - case 'o': - i = atoi(optarg); - if (i != 0) - appl_args->out_mode = PKTOUT_QUEUE; - break; - case 'd': - appl_args->dst_change = atoi(optarg); - break; - case 's': - appl_args->src_change = atoi(optarg); - break; - case 'e': - appl_args->error_check = atoi(optarg); - break; - case 'g': - appl_args->num_groups = atoi(optarg); - break; - case 'h': - usage(argv[0]); - exit(EXIT_SUCCESS); - break; - default: - break; - } - } - - if (appl_args->if_count == 0) { - usage(argv[0]); - exit(EXIT_FAILURE); - } - if (appl_args->addr_count != 0 && - appl_args->addr_count != appl_args->if_count) { - printf("Number of destination addresses differs from number" - " of interfaces\n"); - usage(argv[0]); - exit(EXIT_FAILURE); - } - - optind = 1; /* reset 'extern optind' from the getopt lib */ -} - -/** - * Print system and application info - */ -static void print_info(char *progname, appl_args_t *appl_args) -{ - int i; - - printf("\n" - "ODP system info\n" - "---------------\n" - "ODP API version: %s\n" - "ODP impl name: %s\n" - "CPU model: %s\n" - "CPU freq (hz): %" PRIu64 "\n" - "Cache line size: %i\n" - "CPU count: %i\n" - "\n", - odp_version_api_str(), odp_version_impl_name(), - odp_cpu_model_str(), odp_cpu_hz_max(), - odp_sys_cache_line_size(), odp_cpu_count()); - - printf("Running ODP appl: \"%s\"\n" - "-----------------\n" - "IF-count: %i\n" - "Using IFs: ", - progname, appl_args->if_count); - for (i = 0; i < appl_args->if_count; ++i) - printf(" %s", appl_args->if_names[i]); - printf("\n" - "Mode: "); - if (appl_args->in_mode == DIRECT_RECV) - printf("PKTIN_DIRECT, "); - else if (appl_args->in_mode == PLAIN_QUEUE) - printf("PKTIN_QUEUE, "); - else if (appl_args->in_mode == SCHED_PARALLEL) - printf("PKTIN_SCHED_PARALLEL, "); - else if (appl_args->in_mode == SCHED_ATOMIC) - printf("PKTIN_SCHED_ATOMIC, "); - else if (appl_args->in_mode == SCHED_ORDERED) - printf("PKTIN_SCHED_ORDERED, "); - - if (appl_args->out_mode) - printf("PKTOUT_QUEUE"); - else - printf("PKTOUT_DIRECT"); - - printf("\n\n"); - fflush(NULL); -} - -static void gbl_args_init(args_t *args) -{ - int pktio, queue; - - memset(args, 0, sizeof(args_t)); - - for (pktio = 0; pktio < MAX_PKTIOS; pktio++) { - args->pktios[pktio].pktio = ODP_PKTIO_INVALID; - - for (queue = 0; queue < MAX_QUEUES; queue++) - args->pktios[pktio].rx_q[queue] = ODP_QUEUE_INVALID; - } -} - -static void create_groups(int num, odp_schedule_group_t *group) -{ - int i; - odp_thrmask_t zero; - - odp_thrmask_zero(&zero); - - /* Create groups */ - for (i = 0; i < num; i++) { - group[i] = odp_schedule_group_create(NULL, &zero); - - if (group[i] == ODP_SCHED_GROUP_INVALID) { - LOG_ERR("Group create failed\n"); - exit(EXIT_FAILURE); - } - } -} - -/** - * ODP L2 forwarding main function - */ -int main(int argc, char *argv[]) -{ - odph_odpthread_t thread_tbl[MAX_WORKERS]; - odp_pool_t pool; - int i; - int cpu; - int num_workers; - odp_shm_t shm; - odp_cpumask_t cpumask; - char cpumaskstr[ODP_CPUMASK_STR_SIZE]; - odph_ethaddr_t new_addr; - odp_pool_param_t params; - int ret; - stats_t *stats; - int if_count; - int (*thr_run_func)(void *); - odp_instance_t instance; - int num_groups; - odp_schedule_group_t group[MAX_PKTIOS]; - - /* Signal handler has to be registered before global init in case ODP - * implementation creates internal threads/processes. */ - signal(SIGINT, sig_handler); - - /* Init ODP before calling anything else */ - if (odp_init_global(&instance, NULL, NULL)) { - LOG_ERR("Error: ODP global init failed.\n"); - exit(EXIT_FAILURE); - } - - /* Init this thread */ - if (odp_init_local(instance, ODP_THREAD_CONTROL)) { - LOG_ERR("Error: ODP local init failed.\n"); - exit(EXIT_FAILURE); - } - - /* Reserve memory for args from shared mem */ - shm = odp_shm_reserve("shm_args", sizeof(args_t), - ODP_CACHE_LINE_SIZE, 0); - gbl_args = odp_shm_addr(shm); - - if (gbl_args == NULL) { - LOG_ERR("Error: shared mem alloc failed.\n"); - exit(EXIT_FAILURE); - } - gbl_args_init(gbl_args); - - /* Parse and store the application arguments */ - parse_args(argc, argv, &gbl_args->appl); - - if (sched_mode(gbl_args->appl.in_mode)) - gbl_args->appl.sched_mode = 1; - - /* Print both system and application information */ - print_info(NO_PATH(argv[0]), &gbl_args->appl); - - /* Default to system CPU count unless user specified */ - num_workers = MAX_WORKERS; - if (gbl_args->appl.cpu_count) - num_workers = gbl_args->appl.cpu_count; - - /* Get default worker cpumask */ - num_workers = odp_cpumask_default_worker(&cpumask, num_workers); - (void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr)); - - gbl_args->appl.num_workers = num_workers; - - for (i = 0; i < num_workers; i++) - gbl_args->thread[i].thr_idx = i; - - if_count = gbl_args->appl.if_count; - - num_groups = gbl_args->appl.num_groups; - - printf("num worker threads: %i\n", num_workers); - printf("first CPU: %i\n", odp_cpumask_first(&cpumask)); - printf("cpu mask: %s\n", cpumaskstr); - - if (num_groups) - printf("num groups: %i\n", num_groups); - - printf("\n"); - - if (num_groups > if_count || num_groups > num_workers) { - LOG_ERR("Too many groups. Number of groups may not exceed " - "number of interfaces or workers.\n"); - exit(EXIT_FAILURE); - } - - /* Create packet pool */ - odp_pool_param_init(¶ms); - params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE; - params.pkt.len = SHM_PKT_POOL_BUF_SIZE; - params.pkt.num = SHM_PKT_POOL_SIZE; - params.type = ODP_POOL_PACKET; - - pool = odp_pool_create("packet pool", ¶ms); - - if (pool == ODP_POOL_INVALID) { - LOG_ERR("Error: packet pool create failed.\n"); - exit(EXIT_FAILURE); - } - odp_pool_print(pool); - - if (odp_pktio_max_index() >= MAX_PKTIO_INDEXES) - LOG_DBG("Warning: max pktio index (%u) is too large\n", - odp_pktio_max_index()); - - bind_workers(); - - /* Default */ - if (num_groups == 0) { - group[0] = ODP_SCHED_GROUP_ALL; - num_groups = 1; - } else { - create_groups(num_groups, group); - } - - for (i = 0; i < if_count; ++i) { - const char *dev = gbl_args->appl.if_names[i]; - int num_rx, num_tx; - odp_schedule_group_t grp; - - /* A queue per worker in scheduled mode */ - num_rx = num_workers; - num_tx = num_workers; - - if (!gbl_args->appl.sched_mode) { - /* A queue per assigned worker */ - num_rx = gbl_args->pktios[i].num_rx_thr; - num_tx = gbl_args->pktios[i].num_tx_thr; - } - - /* Round robin pktios to groups */ - grp = group[i % num_groups]; - - if (create_pktio(dev, i, num_rx, num_tx, pool, grp)) - exit(EXIT_FAILURE); - - /* Save interface ethernet address */ - if (odp_pktio_mac_addr(gbl_args->pktios[i].pktio, - gbl_args->port_eth_addr[i].addr, - ODPH_ETHADDR_LEN) != ODPH_ETHADDR_LEN) { - LOG_ERR("Error: interface ethernet address unknown\n"); - exit(EXIT_FAILURE); - } - - /* Save destination eth address */ - if (gbl_args->appl.dst_change) { - /* 02:00:00:00:00:XX */ - memset(&new_addr, 0, sizeof(odph_ethaddr_t)); - if (gbl_args->appl.addr_count) { - memcpy(&new_addr, &gbl_args->appl.addrs[i], - sizeof(odph_ethaddr_t)); - } else { - new_addr.addr[0] = 0x02; - new_addr.addr[5] = i; - } - gbl_args->dst_eth_addr[i] = new_addr; - } - } - - gbl_args->pktios[i].pktio = ODP_PKTIO_INVALID; - - bind_queues(); - - init_port_lookup_tbl(); - - if (!gbl_args->appl.sched_mode) - print_port_mapping(); - - memset(thread_tbl, 0, sizeof(thread_tbl)); - - stats = gbl_args->stats; - - odp_barrier_init(&gbl_args->init_barrier, num_workers + 1); - odp_barrier_init(&gbl_args->term_barrier, num_workers + 1); - - if (gbl_args->appl.in_mode == DIRECT_RECV) - thr_run_func = run_worker_direct_mode; - else if (gbl_args->appl.in_mode == PLAIN_QUEUE) - thr_run_func = run_worker_plain_queue_mode; - else /* SCHED_PARALLEL / SCHED_ATOMIC / SCHED_ORDERED */ - thr_run_func = run_worker_sched_mode; - - /* Create worker threads */ - cpu = odp_cpumask_first(&cpumask); - for (i = 0; i < num_workers; ++i) { - odp_cpumask_t thd_mask; - odph_odpthread_params_t thr_params; - - memset(&thr_params, 0, sizeof(thr_params)); - thr_params.start = thr_run_func; - thr_params.arg = &gbl_args->thread[i]; - thr_params.thr_type = ODP_THREAD_WORKER; - thr_params.instance = instance; - - /* Round robin threads to groups */ - gbl_args->thread[i].num_groups = 1; - gbl_args->thread[i].group[0] = group[i % num_groups]; - - gbl_args->thread[i].stats = &stats[i]; - - odp_cpumask_zero(&thd_mask); - odp_cpumask_set(&thd_mask, cpu); - odph_odpthreads_create(&thread_tbl[i], &thd_mask, - &thr_params); - cpu = odp_cpumask_next(&cpumask, cpu); - } - - /* Start packet receive and transmit */ - for (i = 0; i < if_count; ++i) { - odp_pktio_t pktio; - - pktio = gbl_args->pktios[i].pktio; - ret = odp_pktio_start(pktio); - if (ret) { - LOG_ERR("Error: unable to start %s\n", - gbl_args->appl.if_names[i]); - exit(EXIT_FAILURE); - } - } - - ret = print_speed_stats(num_workers, stats, gbl_args->appl.time, - gbl_args->appl.accuracy); - - for (i = 0; i < if_count; ++i) { - if (odp_pktio_stop(gbl_args->pktios[i].pktio)) { - LOG_ERR("Error: unable to stop %s\n", - gbl_args->appl.if_names[i]); - exit(EXIT_FAILURE); - } - } - - exit_threads = 1; - if (gbl_args->appl.in_mode != DIRECT_RECV) - odp_barrier_wait(&gbl_args->term_barrier); - - /* Master thread waits for other threads to exit */ - for (i = 0; i < num_workers; ++i) - odph_odpthreads_join(&thread_tbl[i]); - - for (i = 0; i < if_count; ++i) { - if (odp_pktio_close(gbl_args->pktios[i].pktio)) { - LOG_ERR("Error: unable to close %s\n", - gbl_args->appl.if_names[i]); - exit(EXIT_FAILURE); - } - } - - free(gbl_args->appl.if_names); - free(gbl_args->appl.if_str); - - if (odp_pool_destroy(pool)) { - LOG_ERR("Error: pool destroy\n"); - exit(EXIT_FAILURE); - } - - if (odp_shm_free(shm)) { - LOG_ERR("Error: shm free\n"); - exit(EXIT_FAILURE); - } - - if (odp_term_local()) { - LOG_ERR("Error: term local\n"); - exit(EXIT_FAILURE); - } - - if (odp_term_global(instance)) { - LOG_ERR("Error: term global\n"); - exit(EXIT_FAILURE); - } - - return ret; -} |