From: Pavan Nikhilesh Date: Wed, 30 Oct 2019 16:26:42 +0000 (+0530) Subject: examples/l2fwd-event: add default poll mode routines X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=4ff457986f;p=dpdk.git examples/l2fwd-event: add default poll mode routines Add the default l2fwd poll mode routines similar to examples/l2fwd. Signed-off-by: Sunil Kumar Kori Signed-off-by: Pavan Nikhilesh Acked-by: Nipun Gupta Acked-by: Jerin Jacob --- diff --git a/MAINTAINERS b/MAINTAINERS index c67b5f3f68..e34f05c60e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1503,6 +1503,11 @@ M: Tomasz Kantecki F: doc/guides/sample_app_ug/l2_forward_cat.rst F: examples/l2fwd-cat/ +M: Sunil Kumar Kori +M: Pavan Nikhilesh +T: git://dpdk.org/next/dpdk-next-eventdev +F: examples/l2fwd-event/ + F: examples/l3fwd/ F: doc/guides/sample_app_ug/l3_forward.rst diff --git a/examples/Makefile b/examples/Makefile index 75c56710f7..c4d1343def 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -36,6 +36,7 @@ endif DIRS-$(CONFIG_RTE_LIBRTE_HASH) += ipv4_multicast DIRS-$(CONFIG_RTE_LIBRTE_KNI) += kni DIRS-y += l2fwd +DIRS-y += l2fwd-event ifneq ($(PQOS_INSTALL_PATH),) DIRS-y += l2fwd-cat endif diff --git a/examples/l2fwd-event/Makefile b/examples/l2fwd-event/Makefile new file mode 100644 index 0000000000..73f02dd3bd --- /dev/null +++ b/examples/l2fwd-event/Makefile @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(C) 2019 Marvell International Ltd. +# + +# binary name +APP = l2fwd-event + +# all source are stored in SRCS-y +SRCS-y := main.c +SRCS-y += l2fwd_poll.c +SRCS-y += l2fwd_common.c + +# Build using pkg-config variables if possible +ifeq ($(shell pkg-config --exists libdpdk && echo 0),0) + +all: shared +.PHONY: shared static +shared: build/$(APP)-shared + ln -sf $(APP)-shared build/$(APP) +static: build/$(APP)-static + ln -sf $(APP)-static build/$(APP) + +PKGCONF=pkg-config --define-prefix + +PC_FILE := $(shell $(PKGCONF) --path libdpdk) +CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk) +LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk) +LDFLAGS_STATIC = -Wl,-Bstatic $(shell $(PKGCONF) --static --libs libdpdk) + +build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build + $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED) + +build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build + $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC) + +build: + @mkdir -p $@ + +.PHONY: clean +clean: + rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared + test -d build && rmdir -p build || true + +else # Build using legacy build system + +ifeq ($(RTE_SDK),) +$(error "Please define RTE_SDK environment variable") +endif + +# Default target, detect a build directory, by looking for a path with a .config +RTE_TARGET ?= $(notdir $(abspath $(dir $(firstword $(wildcard $(RTE_SDK)/*/.config))))) + +include $(RTE_SDK)/mk/rte.vars.mk + +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) + +include $(RTE_SDK)/mk/rte.extapp.mk +endif diff --git a/examples/l2fwd-event/l2fwd_common.c b/examples/l2fwd-event/l2fwd_common.c new file mode 100644 index 0000000000..c206415d07 --- /dev/null +++ b/examples/l2fwd-event/l2fwd_common.c @@ -0,0 +1,91 @@ +#include "l2fwd_common.h" + +int +l2fwd_event_init_ports(struct l2fwd_resources *rsrc) +{ + uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; + uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; + struct rte_eth_conf port_conf = { + .rxmode = { + .max_rx_pkt_len = RTE_ETHER_MAX_LEN, + .split_hdr_size = 0, + }, + .txmode = { + .mq_mode = ETH_MQ_TX_NONE, + }, + }; + uint16_t nb_ports_available = 0; + uint16_t port_id; + int ret; + + /* Initialise each port */ + RTE_ETH_FOREACH_DEV(port_id) { + struct rte_eth_conf local_port_conf = port_conf; + struct rte_eth_dev_info dev_info; + struct rte_eth_rxconf rxq_conf; + struct rte_eth_txconf txq_conf; + + /* skip ports that are not enabled */ + if ((rsrc->enabled_port_mask & (1 << port_id)) == 0) { + printf("Skipping disabled port %u\n", port_id); + continue; + } + nb_ports_available++; + + /* init port */ + printf("Initializing port %u... ", port_id); + fflush(stdout); + rte_eth_dev_info_get(port_id, &dev_info); + if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) + local_port_conf.txmode.offloads |= + DEV_TX_OFFLOAD_MBUF_FAST_FREE; + ret = rte_eth_dev_configure(port_id, 1, 1, &local_port_conf); + if (ret < 0) + rte_panic("Cannot configure device: err=%d, port=%u\n", + ret, port_id); + + ret = rte_eth_dev_adjust_nb_rx_tx_desc(port_id, &nb_rxd, + &nb_txd); + if (ret < 0) + rte_panic("Cannot adjust number of descriptors: err=%d, port=%u\n", + ret, port_id); + + rte_eth_macaddr_get(port_id, &rsrc->eth_addr[port_id]); + + /* init one RX queue */ + fflush(stdout); + rxq_conf = dev_info.default_rxconf; + rxq_conf.offloads = local_port_conf.rxmode.offloads; + ret = rte_eth_rx_queue_setup(port_id, 0, nb_rxd, + rte_eth_dev_socket_id(port_id), + &rxq_conf, + rsrc->pktmbuf_pool); + if (ret < 0) + rte_panic("rte_eth_rx_queue_setup:err=%d, port=%u\n", + ret, port_id); + + /* init one TX queue on each port */ + fflush(stdout); + txq_conf = dev_info.default_txconf; + txq_conf.offloads = local_port_conf.txmode.offloads; + ret = rte_eth_tx_queue_setup(port_id, 0, nb_txd, + rte_eth_dev_socket_id(port_id), + &txq_conf); + if (ret < 0) + rte_panic("rte_eth_tx_queue_setup:err=%d, port=%u\n", + ret, port_id); + + rte_eth_promiscuous_enable(port_id); + + printf("Port %u,MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n", + port_id, + rsrc->eth_addr[port_id].addr_bytes[0], + rsrc->eth_addr[port_id].addr_bytes[1], + rsrc->eth_addr[port_id].addr_bytes[2], + rsrc->eth_addr[port_id].addr_bytes[3], + rsrc->eth_addr[port_id].addr_bytes[4], + rsrc->eth_addr[port_id].addr_bytes[5]); + } + + return nb_ports_available; +} diff --git a/examples/l2fwd-event/l2fwd_common.h b/examples/l2fwd-event/l2fwd_common.h new file mode 100644 index 0000000000..7b74f92b3f --- /dev/null +++ b/examples/l2fwd-event/l2fwd_common.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2019 Marvell International Ltd. + */ + +#ifndef __L2FWD_COMMON_H__ +#define __L2FWD_COMMON_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_PKT_BURST 32 +#define MAX_RX_QUEUE_PER_LCORE 16 +#define MAX_TX_QUEUE_PER_PORT 16 + +#define RTE_TEST_RX_DESC_DEFAULT 1024 +#define RTE_TEST_TX_DESC_DEFAULT 1024 + +#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */ +#define MEMPOOL_CACHE_SIZE 256 + +#define DEFAULT_TIMER_PERIOD 10 /* default period is 10 seconds */ +#define MAX_TIMER_PERIOD 86400 /* 1 day max */ + +/* Per-port statistics struct */ +struct l2fwd_port_statistics { + uint64_t dropped; + uint64_t tx; + uint64_t rx; +} __rte_cache_aligned; + +struct l2fwd_resources { + volatile uint8_t force_quit; + uint8_t mac_updating; + uint8_t rx_queue_per_lcore; + uint16_t nb_rxd; + uint16_t nb_txd; + uint32_t enabled_port_mask; + uint64_t timer_period; + struct rte_mempool *pktmbuf_pool; + uint32_t dst_ports[RTE_MAX_ETHPORTS]; + struct rte_ether_addr eth_addr[RTE_MAX_ETHPORTS]; + struct l2fwd_port_statistics port_stats[RTE_MAX_ETHPORTS]; + void *poll_rsrc; +} __rte_cache_aligned; + +static __rte_always_inline void +l2fwd_mac_updating(struct rte_mbuf *m, uint32_t dest_port_id, + struct rte_ether_addr *addr) +{ + struct rte_ether_hdr *eth; + void *tmp; + + eth = rte_pktmbuf_mtod(m, struct rte_ether_hdr *); + + /* 02:00:00:00:00:xx */ + tmp = ð->d_addr.addr_bytes[0]; + *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dest_port_id << 40); + + /* src addr */ + rte_ether_addr_copy(addr, ð->s_addr); +} + +static __rte_always_inline struct l2fwd_resources * +l2fwd_get_rsrc(void) +{ + static const char name[RTE_MEMZONE_NAMESIZE] = "rsrc"; + const struct rte_memzone *mz; + + mz = rte_memzone_lookup(name); + if (mz != NULL) + return mz->addr; + + mz = rte_memzone_reserve(name, sizeof(struct l2fwd_resources), 0, 0); + if (mz != NULL) { + struct l2fwd_resources *rsrc = mz->addr; + + memset(rsrc, 0, sizeof(struct l2fwd_resources)); + rsrc->mac_updating = true; + rsrc->rx_queue_per_lcore = 1; + rsrc->timer_period = 10 * rte_get_timer_hz(); + + return mz->addr; + } + + rte_panic("Unable to allocate memory for l2fwd resources\n"); + + return NULL; +} + +int l2fwd_event_init_ports(struct l2fwd_resources *rsrc); + +#endif /* __L2FWD_COMMON_H__ */ diff --git a/examples/l2fwd-event/l2fwd_poll.c b/examples/l2fwd-event/l2fwd_poll.c new file mode 100644 index 0000000000..cc96b14cb6 --- /dev/null +++ b/examples/l2fwd-event/l2fwd_poll.c @@ -0,0 +1,177 @@ +#include "l2fwd_poll.h" + +static inline void +l2fwd_poll_simple_forward(struct l2fwd_resources *rsrc, struct rte_mbuf *m, + uint32_t portid) +{ + struct rte_eth_dev_tx_buffer *buffer; + uint32_t dst_port; + int sent; + + dst_port = rsrc->dst_ports[portid]; + + if (rsrc->mac_updating) + l2fwd_mac_updating(m, dst_port, &rsrc->eth_addr[dst_port]); + + buffer = ((struct l2fwd_poll_resources *)rsrc->poll_rsrc)->tx_buffer[ + dst_port]; + sent = rte_eth_tx_buffer(dst_port, 0, buffer, m); + if (sent) + rsrc->port_stats[dst_port].tx += sent; +} + +/* main poll mode processing loop */ +static void +l2fwd_poll_main_loop(struct l2fwd_resources *rsrc) +{ + uint64_t prev_tsc, diff_tsc, cur_tsc, drain_tsc; + struct l2fwd_poll_resources *poll_rsrc = rsrc->poll_rsrc; + struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; + struct rte_eth_dev_tx_buffer *buf; + struct lcore_queue_conf *qconf; + uint32_t i, j, port_id, nb_rx; + struct rte_mbuf *m; + uint32_t lcore_id; + int32_t sent; + + drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * + BURST_TX_DRAIN_US; + prev_tsc = 0; + + lcore_id = rte_lcore_id(); + qconf = &poll_rsrc->lcore_queue_conf[lcore_id]; + + if (qconf->n_rx_port == 0) { + printf("lcore %u has nothing to do\n", lcore_id); + return; + } + + printf("entering main loop on lcore %u\n", lcore_id); + + for (i = 0; i < qconf->n_rx_port; i++) { + + port_id = qconf->rx_port_list[i]; + printf(" -- lcoreid=%u port_id=%u\n", lcore_id, port_id); + + } + + while (!rsrc->force_quit) { + + cur_tsc = rte_rdtsc(); + + /* + * TX burst queue drain + */ + diff_tsc = cur_tsc - prev_tsc; + if (unlikely(diff_tsc > drain_tsc)) { + for (i = 0; i < qconf->n_rx_port; i++) { + port_id = + rsrc->dst_ports[qconf->rx_port_list[i]]; + buf = poll_rsrc->tx_buffer[port_id]; + sent = rte_eth_tx_buffer_flush(port_id, 0, buf); + if (sent) + rsrc->port_stats[port_id].tx += sent; + } + + prev_tsc = cur_tsc; + } + + /* + * Read packet from RX queues + */ + for (i = 0; i < qconf->n_rx_port; i++) { + + port_id = qconf->rx_port_list[i]; + nb_rx = rte_eth_rx_burst(port_id, 0, pkts_burst, + MAX_PKT_BURST); + + rsrc->port_stats[port_id].rx += nb_rx; + + for (j = 0; j < nb_rx; j++) { + m = pkts_burst[j]; + rte_prefetch0(rte_pktmbuf_mtod(m, void *)); + l2fwd_poll_simple_forward(rsrc, m, port_id); + } + } + } +} + +static void +l2fwd_poll_lcore_config(struct l2fwd_resources *rsrc) +{ + struct l2fwd_poll_resources *poll_rsrc = rsrc->poll_rsrc; + struct lcore_queue_conf *qconf = NULL; + uint32_t rx_lcore_id = 0; + uint16_t port_id; + + /* Initialize the port/queue configuration of each logical core */ + RTE_ETH_FOREACH_DEV(port_id) { + /* skip ports that are not enabled */ + if ((rsrc->enabled_port_mask & (1 << port_id)) == 0) + continue; + + /* get the lcore_id for this port */ + while (rte_lcore_is_enabled(rx_lcore_id) == 0 || + poll_rsrc->lcore_queue_conf[rx_lcore_id].n_rx_port == + rsrc->rx_queue_per_lcore) { + rx_lcore_id++; + if (rx_lcore_id >= RTE_MAX_LCORE) + rte_panic("Not enough cores\n"); + } + + if (qconf != &poll_rsrc->lcore_queue_conf[rx_lcore_id]) { + /* Assigned a new logical core in the loop above. */ + qconf = &poll_rsrc->lcore_queue_conf[rx_lcore_id]; + } + + qconf->rx_port_list[qconf->n_rx_port] = port_id; + qconf->n_rx_port++; + printf("Lcore %u: RX port %u\n", rx_lcore_id, port_id); + } +} + +static void +l2fwd_poll_init_tx_buffers(struct l2fwd_resources *rsrc) +{ + struct l2fwd_poll_resources *poll_rsrc = rsrc->poll_rsrc; + uint16_t port_id; + int ret; + + RTE_ETH_FOREACH_DEV(port_id) { + /* Initialize TX buffers */ + poll_rsrc->tx_buffer[port_id] = rte_zmalloc_socket("tx_buffer", + RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0, + rte_eth_dev_socket_id(port_id)); + if (poll_rsrc->tx_buffer[port_id] == NULL) + rte_panic("Cannot allocate buffer for tx on port %u\n", + port_id); + + rte_eth_tx_buffer_init(poll_rsrc->tx_buffer[port_id], + MAX_PKT_BURST); + + ret = rte_eth_tx_buffer_set_err_callback( + poll_rsrc->tx_buffer[port_id], + rte_eth_tx_buffer_count_callback, + &rsrc->port_stats[port_id].dropped); + if (ret < 0) + rte_panic("Cannot set error callback for tx buffer on port %u\n", + port_id); + } +} + +void +l2fwd_poll_resource_setup(struct l2fwd_resources *rsrc) +{ + struct l2fwd_poll_resources *poll_rsrc; + + poll_rsrc = rte_zmalloc("l2fwd_poll_rsrc", + sizeof(struct l2fwd_poll_resources), 0); + if (poll_rsrc == NULL) + rte_panic("Failed to allocate resources for l2fwd poll mode\n"); + + rsrc->poll_rsrc = poll_rsrc; + l2fwd_poll_lcore_config(rsrc); + l2fwd_poll_init_tx_buffers(rsrc); + + poll_rsrc->poll_main_loop = l2fwd_poll_main_loop; +} diff --git a/examples/l2fwd-event/l2fwd_poll.h b/examples/l2fwd-event/l2fwd_poll.h new file mode 100644 index 0000000000..d59b0c844b --- /dev/null +++ b/examples/l2fwd-event/l2fwd_poll.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2019 Marvell International Ltd. + */ + +#ifndef __L2FWD_POLL_H__ +#define __L2FWD_POLL_H__ + +#include "l2fwd_common.h" + +typedef void (*poll_main_loop_cb)(struct l2fwd_resources *rsrc); + +struct lcore_queue_conf { + uint32_t rx_port_list[MAX_RX_QUEUE_PER_LCORE]; + uint32_t n_rx_port; +} __rte_cache_aligned; + +struct l2fwd_poll_resources { + poll_main_loop_cb poll_main_loop; + struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS]; + struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE]; +}; + +void l2fwd_poll_resource_setup(struct l2fwd_resources *rsrc); + +#endif diff --git a/examples/l2fwd-event/main.c b/examples/l2fwd-event/main.c new file mode 100644 index 0000000000..a4e41ddb40 --- /dev/null +++ b/examples/l2fwd-event/main.c @@ -0,0 +1,446 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2019 Marvell International Ltd. + */ + +#include "l2fwd_poll.h" + +/* display usage */ +static void +l2fwd_event_usage(const char *prgname) +{ + printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n" + " -p PORTMASK: hexadecimal bitmask of ports to configure\n" + " -q NQ: number of queue (=ports) per lcore (default is 1)\n" + " -T PERIOD: statistics will be refreshed each PERIOD seconds " + " (0 to disable, 10 default, 86400 maximum)\n" + " --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n" + " When enabled:\n" + " - The source MAC address is replaced by the TX port MAC address\n" + " - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n", + prgname); +} + +static int +l2fwd_event_parse_portmask(const char *portmask) +{ + char *end = NULL; + unsigned long pm; + + /* parse hexadecimal string */ + pm = strtoul(portmask, &end, 16); + if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) + return -1; + + if (pm == 0) + return -1; + + return pm; +} + +static unsigned int +l2fwd_event_parse_nqueue(const char *q_arg) +{ + char *end = NULL; + unsigned long n; + + /* parse hexadecimal string */ + n = strtoul(q_arg, &end, 10); + if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) + return 0; + if (n == 0) + return 0; + if (n >= MAX_RX_QUEUE_PER_LCORE) + return 0; + + return n; +} + +static int +l2fwd_event_parse_timer_period(const char *q_arg) +{ + char *end = NULL; + int n; + + /* parse number string */ + n = strtol(q_arg, &end, 10); + if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) + return -1; + if (n >= MAX_TIMER_PERIOD) + return -1; + + return n; +} + +static const char short_options[] = + "p:" /* portmask */ + "q:" /* number of queues */ + "T:" /* timer period */ + ; + +#define CMD_LINE_OPT_MAC_UPDATING "mac-updating" +#define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating" + +enum { + /* long options mapped to a short option */ + + /* first long only option value must be >= 256, so that we won't + * conflict with short options + */ + CMD_LINE_OPT_MIN_NUM = 256, +}; + +/* Parse the argument given in the command line of the application */ +static int +l2fwd_event_parse_args(int argc, char **argv, + struct l2fwd_resources *rsrc) +{ + int mac_updating = 1; + struct option lgopts[] = { + { CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1}, + { CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0}, + {NULL, 0, 0, 0} + }; + int opt, ret, timer_secs; + char *prgname = argv[0]; + char **argvopt; + int option_index; + + argvopt = argv; + while ((opt = getopt_long(argc, argvopt, short_options, + lgopts, &option_index)) != EOF) { + + switch (opt) { + /* portmask */ + case 'p': + rsrc->enabled_port_mask = + l2fwd_event_parse_portmask(optarg); + if (rsrc->enabled_port_mask == 0) { + printf("invalid portmask\n"); + l2fwd_event_usage(prgname); + return -1; + } + break; + + /* nqueue */ + case 'q': + rsrc->rx_queue_per_lcore = + l2fwd_event_parse_nqueue(optarg); + if (rsrc->rx_queue_per_lcore == 0) { + printf("invalid queue number\n"); + l2fwd_event_usage(prgname); + return -1; + } + break; + + /* timer period */ + case 'T': + timer_secs = l2fwd_event_parse_timer_period(optarg); + if (timer_secs < 0) { + printf("invalid timer period\n"); + l2fwd_event_usage(prgname); + return -1; + } + rsrc->timer_period = timer_secs; + /* convert to number of cycles */ + rsrc->timer_period *= rte_get_timer_hz(); + break; + + /* long options */ + case 0: + break; + + default: + l2fwd_event_usage(prgname); + return -1; + } + } + + rsrc->mac_updating = mac_updating; + + if (optind >= 0) + argv[optind-1] = prgname; + + ret = optind-1; + optind = 1; /* reset getopt lib */ + return ret; +} + +static int +l2fwd_launch_one_lcore(void *args) +{ + struct l2fwd_resources *rsrc = args; + struct l2fwd_poll_resources *poll_rsrc = rsrc->poll_rsrc; + + poll_rsrc->poll_main_loop(rsrc); + + return 0; +} + +/* Check the link status of all ports in up to 9s, and print them finally */ +static void +check_all_ports_link_status(struct l2fwd_resources *rsrc, + uint32_t port_mask) +{ +#define CHECK_INTERVAL 100 /* 100ms */ +#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ + uint16_t port_id; + uint8_t count, all_ports_up, print_flag = 0; + struct rte_eth_link link; + + printf("\nChecking link status..."); + fflush(stdout); + for (count = 0; count <= MAX_CHECK_TIME; count++) { + if (rsrc->force_quit) + return; + all_ports_up = 1; + RTE_ETH_FOREACH_DEV(port_id) { + if (rsrc->force_quit) + return; + if ((port_mask & (1 << port_id)) == 0) + continue; + memset(&link, 0, sizeof(link)); + rte_eth_link_get_nowait(port_id, &link); + /* print link status if flag set */ + if (print_flag == 1) { + if (link.link_status) + printf( + "Port%d Link Up. Speed %u Mbps - %s\n", + port_id, link.link_speed, + (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? + ("full-duplex") : ("half-duplex\n")); + else + printf("Port %d Link Down\n", port_id); + continue; + } + /* clear all_ports_up flag if any link down */ + if (link.link_status == ETH_LINK_DOWN) { + all_ports_up = 0; + break; + } + } + /* after finally printing all link status, get out */ + if (print_flag == 1) + break; + + if (all_ports_up == 0) { + printf("."); + fflush(stdout); + rte_delay_ms(CHECK_INTERVAL); + } + + /* set the print_flag if all ports up or timeout */ + if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { + print_flag = 1; + printf("done\n"); + } + } +} + +/* Print out statistics on packets dropped */ +static void +print_stats(struct l2fwd_resources *rsrc) +{ + uint64_t total_packets_dropped, total_packets_tx, total_packets_rx; + uint32_t port_id; + + total_packets_dropped = 0; + total_packets_tx = 0; + total_packets_rx = 0; + + const char clr[] = {27, '[', '2', 'J', '\0' }; + const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0' }; + + /* Clear screen and move to top left */ + printf("%s%s", clr, topLeft); + + printf("\nPort statistics ===================================="); + + for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { + /* skip disabled ports */ + if ((rsrc->enabled_port_mask & (1 << port_id)) == 0) + continue; + printf("\nStatistics for port %u ------------------------------" + "\nPackets sent: %24"PRIu64 + "\nPackets received: %20"PRIu64 + "\nPackets dropped: %21"PRIu64, + port_id, + rsrc->port_stats[port_id].tx, + rsrc->port_stats[port_id].rx, + rsrc->port_stats[port_id].dropped); + + total_packets_dropped += + rsrc->port_stats[port_id].dropped; + total_packets_tx += rsrc->port_stats[port_id].tx; + total_packets_rx += rsrc->port_stats[port_id].rx; + } + printf("\nAggregate statistics ===============================" + "\nTotal packets sent: %18"PRIu64 + "\nTotal packets received: %14"PRIu64 + "\nTotal packets dropped: %15"PRIu64, + total_packets_tx, + total_packets_rx, + total_packets_dropped); + printf("\n====================================================\n"); +} + +static void +l2fwd_event_print_stats(struct l2fwd_resources *rsrc) +{ + uint64_t prev_tsc = 0, diff_tsc, cur_tsc, timer_tsc = 0; + const uint64_t timer_period = rsrc->timer_period; + + while (!rsrc->force_quit) { + /* if timer is enabled */ + if (timer_period > 0) { + cur_tsc = rte_rdtsc(); + diff_tsc = cur_tsc - prev_tsc; + + /* advance the timer */ + timer_tsc += diff_tsc; + + /* if timer has reached its timeout */ + if (unlikely(timer_tsc >= timer_period)) { + print_stats(rsrc); + /* reset the timer */ + timer_tsc = 0; + } + prev_tsc = cur_tsc; + } + } +} + + +static void +signal_handler(int signum) +{ + struct l2fwd_resources *rsrc = l2fwd_get_rsrc(); + if (signum == SIGINT || signum == SIGTERM) { + printf("\n\nSignal %d received, preparing to exit...\n", + signum); + rsrc->force_quit = true; + } +} + +int +main(int argc, char **argv) +{ + struct l2fwd_resources *rsrc; + uint16_t nb_ports_available = 0; + uint32_t nb_ports_in_mask = 0; + uint16_t port_id, last_port; + uint32_t nb_mbufs; + uint16_t nb_ports; + int ret; + + /* init EAL */ + ret = rte_eal_init(argc, argv); + if (ret < 0) + rte_panic("Invalid EAL arguments\n"); + argc -= ret; + argv += ret; + + rsrc = l2fwd_get_rsrc(); + + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + + /* parse application arguments (after the EAL ones) */ + ret = l2fwd_event_parse_args(argc, argv, rsrc); + if (ret < 0) + rte_panic("Invalid L2FWD arguments\n"); + + printf("MAC updating %s\n", rsrc->mac_updating ? "enabled" : + "disabled"); + + nb_ports = rte_eth_dev_count_avail(); + if (nb_ports == 0) + rte_panic("No Ethernet ports - bye\n"); + + /* check port mask to possible port mask */ + if (rsrc->enabled_port_mask & ~((1 << nb_ports) - 1)) + rte_panic("Invalid portmask; possible (0x%x)\n", + (1 << nb_ports) - 1); + + /* reset l2fwd_dst_ports */ + for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) + rsrc->dst_ports[port_id] = 0; + last_port = 0; + + /* + * Each logical core is assigned a dedicated TX queue on each port. + */ + RTE_ETH_FOREACH_DEV(port_id) { + /* skip ports that are not enabled */ + if ((rsrc->enabled_port_mask & (1 << port_id)) == 0) + continue; + + if (nb_ports_in_mask % 2) { + rsrc->dst_ports[port_id] = last_port; + rsrc->dst_ports[last_port] = port_id; + } else { + last_port = port_id; + } + + nb_ports_in_mask++; + } + if (nb_ports_in_mask % 2) { + printf("Notice: odd number of ports in portmask.\n"); + rsrc->dst_ports[last_port] = last_port; + } + + nb_mbufs = RTE_MAX(nb_ports * (RTE_TEST_RX_DESC_DEFAULT + + RTE_TEST_TX_DESC_DEFAULT + + MAX_PKT_BURST + rte_lcore_count() * + MEMPOOL_CACHE_SIZE), 8192U); + + /* create the mbuf pool */ + rsrc->pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", + nb_mbufs, MEMPOOL_CACHE_SIZE, 0, + RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); + if (rsrc->pktmbuf_pool == NULL) + rte_panic("Cannot init mbuf pool\n"); + + nb_ports_available = l2fwd_event_init_ports(rsrc); + if (!nb_ports_available) + rte_panic("All available ports are disabled. Please set portmask.\n"); + + l2fwd_poll_resource_setup(rsrc); + + /* initialize port stats */ + memset(&rsrc->port_stats, 0, + sizeof(struct l2fwd_port_statistics)); + + /* All settings are done. Now enable eth devices */ + RTE_ETH_FOREACH_DEV(port_id) { + /* skip ports that are not enabled */ + if ((rsrc->enabled_port_mask & + (1 << port_id)) == 0) + continue; + + ret = rte_eth_dev_start(port_id); + if (ret < 0) + rte_panic("rte_eth_dev_start:err=%d, port=%u\n", ret, + port_id); + } + + check_all_ports_link_status(rsrc, rsrc->enabled_port_mask); + + /* launch per-lcore init on every lcore */ + rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, rsrc, + SKIP_MASTER); + l2fwd_event_print_stats(rsrc); + rte_eal_mp_wait_lcore(); + + RTE_ETH_FOREACH_DEV(port_id) { + if ((rsrc->enabled_port_mask & + (1 << port_id)) == 0) + continue; + printf("Closing port %d...", port_id); + rte_eth_dev_stop(port_id); + rte_eth_dev_close(port_id); + printf(" Done\n"); + } + printf("Bye...\n"); + + return 0; +} diff --git a/examples/l2fwd-event/meson.build b/examples/l2fwd-event/meson.build new file mode 100644 index 0000000000..c936aa72e8 --- /dev/null +++ b/examples/l2fwd-event/meson.build @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(C) 2019 Marvell International Ltd. +# + +# meson file, for building this example as part of a main DPDK build. +# +# To build this example as a standalone application with an already-installed +# DPDK instance, use 'make' + +deps += 'eventdev' +sources = files( + 'main.c', + 'l2fwd_poll.c', + 'l2fwd_common.c', +) diff --git a/examples/meson.build b/examples/meson.build index 98ae50a498..9d468706de 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -20,7 +20,7 @@ all_examples = [ 'ip_fragmentation', 'ip_pipeline', 'ip_reassembly', 'ipsec-secgw', 'ipv4_multicast', 'kni', - 'l2fwd', 'l2fwd-cat', + 'l2fwd', 'l2fwd-cat', 'l2fwd-event', 'l2fwd-crypto', 'l2fwd-jobstats', 'l2fwd-keepalive', 'l3fwd', 'l3fwd-acl', 'l3fwd-power',