13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 23998e2a0SBruce Richardson * Copyright(c) 2010-2015 Intel Corporation 37107e471SBruce Richardson */ 47107e471SBruce Richardson 57107e471SBruce Richardson #include <stdint.h> 67107e471SBruce Richardson #include <inttypes.h> 77107e471SBruce Richardson #include <rte_eal.h> 87107e471SBruce Richardson #include <rte_ethdev.h> 97107e471SBruce Richardson #include <rte_cycles.h> 107107e471SBruce Richardson #include <rte_lcore.h> 117107e471SBruce Richardson #include <rte_mbuf.h> 127107e471SBruce Richardson 13867a6c66SKevin Laatz #define RX_RING_SIZE 1024 14867a6c66SKevin Laatz #define TX_RING_SIZE 1024 157107e471SBruce Richardson 167107e471SBruce Richardson #define NUM_MBUFS 8191 177107e471SBruce Richardson #define MBUF_CACHE_SIZE 250 187107e471SBruce Richardson #define BURST_SIZE 32 197107e471SBruce Richardson 207107e471SBruce Richardson static const struct rte_eth_conf port_conf_default = { 215d98dd08SShahaf Shuler .rxmode = { 2235b2d13fSOlivier Matz .max_rx_pkt_len = RTE_ETHER_MAX_LEN, 235d98dd08SShahaf Shuler }, 247107e471SBruce Richardson }; 257107e471SBruce Richardson 260f91352cSJohn McNamara /* basicfwd.c: Basic DPDK skeleton forwarding example. */ 270f91352cSJohn McNamara 287107e471SBruce Richardson /* 290f91352cSJohn McNamara * Initializes a given port using global settings and with the RX buffers 300f91352cSJohn McNamara * coming from the mbuf_pool passed as a parameter. 317107e471SBruce Richardson */ 327107e471SBruce Richardson static inline int 33f8244c63SZhiyong Yang port_init(uint16_t port, struct rte_mempool *mbuf_pool) 347107e471SBruce Richardson { 357107e471SBruce Richardson struct rte_eth_conf port_conf = port_conf_default; 367107e471SBruce Richardson const uint16_t rx_rings = 1, tx_rings = 1; 3760efb44fSRoman Zhukov uint16_t nb_rxd = RX_RING_SIZE; 3860efb44fSRoman Zhukov uint16_t nb_txd = TX_RING_SIZE; 397107e471SBruce Richardson int retval; 407107e471SBruce Richardson uint16_t q; 415d98dd08SShahaf Shuler struct rte_eth_dev_info dev_info; 425d98dd08SShahaf Shuler struct rte_eth_txconf txconf; 437107e471SBruce Richardson 44a9dbe180SThomas Monjalon if (!rte_eth_dev_is_valid_port(port)) 457107e471SBruce Richardson return -1; 467107e471SBruce Richardson 47089e5ed7SIvan Ilchenko retval = rte_eth_dev_info_get(port, &dev_info); 48089e5ed7SIvan Ilchenko if (retval != 0) { 49089e5ed7SIvan Ilchenko printf("Error during getting device (port %u) info: %s\n", 50089e5ed7SIvan Ilchenko port, strerror(-retval)); 51089e5ed7SIvan Ilchenko return retval; 52089e5ed7SIvan Ilchenko } 53089e5ed7SIvan Ilchenko 545d98dd08SShahaf Shuler if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) 555d98dd08SShahaf Shuler port_conf.txmode.offloads |= 565d98dd08SShahaf Shuler DEV_TX_OFFLOAD_MBUF_FAST_FREE; 575d98dd08SShahaf Shuler 580f91352cSJohn McNamara /* Configure the Ethernet device. */ 597107e471SBruce Richardson retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf); 607107e471SBruce Richardson if (retval != 0) 617107e471SBruce Richardson return retval; 627107e471SBruce Richardson 6360efb44fSRoman Zhukov retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd); 6460efb44fSRoman Zhukov if (retval != 0) 6560efb44fSRoman Zhukov return retval; 6660efb44fSRoman Zhukov 670f91352cSJohn McNamara /* Allocate and set up 1 RX queue per Ethernet port. */ 687107e471SBruce Richardson for (q = 0; q < rx_rings; q++) { 6960efb44fSRoman Zhukov retval = rte_eth_rx_queue_setup(port, q, nb_rxd, 707107e471SBruce Richardson rte_eth_dev_socket_id(port), NULL, mbuf_pool); 717107e471SBruce Richardson if (retval < 0) 727107e471SBruce Richardson return retval; 737107e471SBruce Richardson } 747107e471SBruce Richardson 755d98dd08SShahaf Shuler txconf = dev_info.default_txconf; 765d98dd08SShahaf Shuler txconf.offloads = port_conf.txmode.offloads; 770f91352cSJohn McNamara /* Allocate and set up 1 TX queue per Ethernet port. */ 787107e471SBruce Richardson for (q = 0; q < tx_rings; q++) { 7960efb44fSRoman Zhukov retval = rte_eth_tx_queue_setup(port, q, nb_txd, 805d98dd08SShahaf Shuler rte_eth_dev_socket_id(port), &txconf); 817107e471SBruce Richardson if (retval < 0) 827107e471SBruce Richardson return retval; 837107e471SBruce Richardson } 847107e471SBruce Richardson 850f91352cSJohn McNamara /* Start the Ethernet port. */ 867107e471SBruce Richardson retval = rte_eth_dev_start(port); 877107e471SBruce Richardson if (retval < 0) 887107e471SBruce Richardson return retval; 897107e471SBruce Richardson 900f91352cSJohn McNamara /* Display the port MAC address. */ 916d13ea8eSOlivier Matz struct rte_ether_addr addr; 9270febdcfSIgor Romanov retval = rte_eth_macaddr_get(port, &addr); 9370febdcfSIgor Romanov if (retval != 0) 9470febdcfSIgor Romanov return retval; 9570febdcfSIgor Romanov 967107e471SBruce Richardson printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8 977107e471SBruce Richardson " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n", 98f8244c63SZhiyong Yang port, 997107e471SBruce Richardson addr.addr_bytes[0], addr.addr_bytes[1], 1007107e471SBruce Richardson addr.addr_bytes[2], addr.addr_bytes[3], 1017107e471SBruce Richardson addr.addr_bytes[4], addr.addr_bytes[5]); 1027107e471SBruce Richardson 1030f91352cSJohn McNamara /* Enable RX in promiscuous mode for the Ethernet device. */ 104f430bbceSIvan Ilchenko retval = rte_eth_promiscuous_enable(port); 105f430bbceSIvan Ilchenko if (retval != 0) 106f430bbceSIvan Ilchenko return retval; 1077107e471SBruce Richardson 1087107e471SBruce Richardson return 0; 1097107e471SBruce Richardson } 1107107e471SBruce Richardson 1117107e471SBruce Richardson /* 1120f91352cSJohn McNamara * The lcore main. This is the main thread that does the work, reading from 1130f91352cSJohn McNamara * an input port and writing to an output port. 1147107e471SBruce Richardson */ 115ddcd7640SThomas Monjalon static __rte_noreturn void 1167107e471SBruce Richardson lcore_main(void) 1177107e471SBruce Richardson { 118f8244c63SZhiyong Yang uint16_t port; 1190f91352cSJohn McNamara 1200f91352cSJohn McNamara /* 1210f91352cSJohn McNamara * Check that the port is on the same NUMA node as the polling thread 1220f91352cSJohn McNamara * for best performance. 1230f91352cSJohn McNamara */ 1248728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(port) 125*5ffa60cdSMin Hu (Connor) if (rte_eth_dev_socket_id(port) >= 0 && 1267107e471SBruce Richardson rte_eth_dev_socket_id(port) != 1277107e471SBruce Richardson (int)rte_socket_id()) 1287107e471SBruce Richardson printf("WARNING, port %u is on remote NUMA node to " 1297107e471SBruce Richardson "polling thread.\n\tPerformance will " 1307107e471SBruce Richardson "not be optimal.\n", port); 1317107e471SBruce Richardson 1327107e471SBruce Richardson printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n", 1337107e471SBruce Richardson rte_lcore_id()); 1340f91352cSJohn McNamara 1350f91352cSJohn McNamara /* Run until the application is quit or killed. */ 1367107e471SBruce Richardson for (;;) { 1370f91352cSJohn McNamara /* 1380f91352cSJohn McNamara * Receive packets on a port and forward them on the paired 1390f91352cSJohn McNamara * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc. 1400f91352cSJohn McNamara */ 1418728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(port) { 1420f91352cSJohn McNamara 1430f91352cSJohn McNamara /* Get burst of RX packets, from first port of pair. */ 1447107e471SBruce Richardson struct rte_mbuf *bufs[BURST_SIZE]; 1457107e471SBruce Richardson const uint16_t nb_rx = rte_eth_rx_burst(port, 0, 1467107e471SBruce Richardson bufs, BURST_SIZE); 1470f91352cSJohn McNamara 1487107e471SBruce Richardson if (unlikely(nb_rx == 0)) 1497107e471SBruce Richardson continue; 1500f91352cSJohn McNamara 1510f91352cSJohn McNamara /* Send burst of TX packets, to second port of pair. */ 1527107e471SBruce Richardson const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0, 1537107e471SBruce Richardson bufs, nb_rx); 1540f91352cSJohn McNamara 1550f91352cSJohn McNamara /* Free any unsent packets. */ 1567107e471SBruce Richardson if (unlikely(nb_tx < nb_rx)) { 1577107e471SBruce Richardson uint16_t buf; 1587107e471SBruce Richardson for (buf = nb_tx; buf < nb_rx; buf++) 1597107e471SBruce Richardson rte_pktmbuf_free(bufs[buf]); 1607107e471SBruce Richardson } 1617107e471SBruce Richardson } 1627107e471SBruce Richardson } 1637107e471SBruce Richardson } 1647107e471SBruce Richardson 1650f91352cSJohn McNamara /* 1660f91352cSJohn McNamara * The main function, which does initialization and calls the per-lcore 1670f91352cSJohn McNamara * functions. 1680f91352cSJohn McNamara */ 1697107e471SBruce Richardson int 17098a16481SDavid Marchand main(int argc, char *argv[]) 1717107e471SBruce Richardson { 1727107e471SBruce Richardson struct rte_mempool *mbuf_pool; 1737107e471SBruce Richardson unsigned nb_ports; 174f8244c63SZhiyong Yang uint16_t portid; 1757107e471SBruce Richardson 1760f91352cSJohn McNamara /* Initialize the Environment Abstraction Layer (EAL). */ 1777107e471SBruce Richardson int ret = rte_eal_init(argc, argv); 1787107e471SBruce Richardson if (ret < 0) 1797107e471SBruce Richardson rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); 1800f91352cSJohn McNamara 1817107e471SBruce Richardson argc -= ret; 1827107e471SBruce Richardson argv += ret; 1837107e471SBruce Richardson 1840f91352cSJohn McNamara /* Check that there is an even number of ports to send/receive on. */ 185d9a42a69SThomas Monjalon nb_ports = rte_eth_dev_count_avail(); 1867107e471SBruce Richardson if (nb_ports < 2 || (nb_ports & 1)) 1877107e471SBruce Richardson rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n"); 1887107e471SBruce Richardson 1890f91352cSJohn McNamara /* Creates a new mempool in memory to hold the mbufs. */ 190ea0c20eaSOlivier Matz mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports, 191824cb29cSKonstantin Ananyev MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); 1920f91352cSJohn McNamara 1937107e471SBruce Richardson if (mbuf_pool == NULL) 1947107e471SBruce Richardson rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n"); 1957107e471SBruce Richardson 1960f91352cSJohn McNamara /* Initialize all ports. */ 1978728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) 1987107e471SBruce Richardson if (port_init(portid, mbuf_pool) != 0) 199f8244c63SZhiyong Yang rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu16 "\n", 2007107e471SBruce Richardson portid); 2017107e471SBruce Richardson 2027107e471SBruce Richardson if (rte_lcore_count() > 1) 2030f91352cSJohn McNamara printf("\nWARNING: Too many lcores enabled. Only 1 used.\n"); 2047107e471SBruce Richardson 205cb056611SStephen Hemminger /* Call lcore_main on the main core only. */ 2067107e471SBruce Richardson lcore_main(); 2070f91352cSJohn McNamara 20810aa3757SChengchang Tang /* clean up the EAL */ 20910aa3757SChengchang Tang rte_eal_cleanup(); 21010aa3757SChengchang Tang 2117107e471SBruce Richardson return 0; 2127107e471SBruce Richardson } 213