1a9643ea8Slogwang /*- 2a9643ea8Slogwang * BSD LICENSE 3a9643ea8Slogwang * 4a9643ea8Slogwang * Copyright(c) 2010-2015 Intel Corporation. All rights reserved. 5a9643ea8Slogwang * All rights reserved. 6a9643ea8Slogwang * 7a9643ea8Slogwang * Redistribution and use in source and binary forms, with or without 8a9643ea8Slogwang * modification, are permitted provided that the following conditions 9a9643ea8Slogwang * are met: 10a9643ea8Slogwang * 11a9643ea8Slogwang * * Redistributions of source code must retain the above copyright 12a9643ea8Slogwang * notice, this list of conditions and the following disclaimer. 13a9643ea8Slogwang * * Redistributions in binary form must reproduce the above copyright 14a9643ea8Slogwang * notice, this list of conditions and the following disclaimer in 15a9643ea8Slogwang * the documentation and/or other materials provided with the 16a9643ea8Slogwang * distribution. 17a9643ea8Slogwang * * Neither the name of Intel Corporation nor the names of its 18a9643ea8Slogwang * contributors may be used to endorse or promote products derived 19a9643ea8Slogwang * from this software without specific prior written permission. 20a9643ea8Slogwang * 21a9643ea8Slogwang * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22a9643ea8Slogwang * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23a9643ea8Slogwang * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24a9643ea8Slogwang * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25a9643ea8Slogwang * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26a9643ea8Slogwang * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27a9643ea8Slogwang * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28a9643ea8Slogwang * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29a9643ea8Slogwang * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30a9643ea8Slogwang * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31a9643ea8Slogwang * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32a9643ea8Slogwang */ 33a9643ea8Slogwang 34a9643ea8Slogwang #include <stdint.h> 35a9643ea8Slogwang #include <inttypes.h> 36a9643ea8Slogwang #include <rte_eal.h> 37a9643ea8Slogwang #include <rte_ethdev.h> 38a9643ea8Slogwang #include <rte_cycles.h> 39a9643ea8Slogwang #include <rte_lcore.h> 40a9643ea8Slogwang #include <rte_mbuf.h> 41a9643ea8Slogwang 42a9643ea8Slogwang #define RX_RING_SIZE 128 43a9643ea8Slogwang #define TX_RING_SIZE 512 44a9643ea8Slogwang 45a9643ea8Slogwang #define NUM_MBUFS 8191 46a9643ea8Slogwang #define MBUF_CACHE_SIZE 250 47a9643ea8Slogwang #define BURST_SIZE 32 48a9643ea8Slogwang 49a9643ea8Slogwang static const struct rte_eth_conf port_conf_default = { 50a9643ea8Slogwang .rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN } 51a9643ea8Slogwang }; 52a9643ea8Slogwang 53a9643ea8Slogwang /* basicfwd.c: Basic DPDK skeleton forwarding example. */ 54a9643ea8Slogwang 55a9643ea8Slogwang /* 56a9643ea8Slogwang * Initializes a given port using global settings and with the RX buffers 57a9643ea8Slogwang * coming from the mbuf_pool passed as a parameter. 58a9643ea8Slogwang */ 59a9643ea8Slogwang static inline int 60*2bfe3f2eSlogwang port_init(uint16_t port, struct rte_mempool *mbuf_pool) 61a9643ea8Slogwang { 62a9643ea8Slogwang struct rte_eth_conf port_conf = port_conf_default; 63a9643ea8Slogwang const uint16_t rx_rings = 1, tx_rings = 1; 64*2bfe3f2eSlogwang uint16_t nb_rxd = RX_RING_SIZE; 65*2bfe3f2eSlogwang uint16_t nb_txd = TX_RING_SIZE; 66a9643ea8Slogwang int retval; 67a9643ea8Slogwang uint16_t q; 68a9643ea8Slogwang 69a9643ea8Slogwang if (port >= rte_eth_dev_count()) 70a9643ea8Slogwang return -1; 71a9643ea8Slogwang 72a9643ea8Slogwang /* Configure the Ethernet device. */ 73a9643ea8Slogwang retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf); 74a9643ea8Slogwang if (retval != 0) 75a9643ea8Slogwang return retval; 76a9643ea8Slogwang 77*2bfe3f2eSlogwang retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd); 78*2bfe3f2eSlogwang if (retval != 0) 79*2bfe3f2eSlogwang return retval; 80*2bfe3f2eSlogwang 81a9643ea8Slogwang /* Allocate and set up 1 RX queue per Ethernet port. */ 82a9643ea8Slogwang for (q = 0; q < rx_rings; q++) { 83*2bfe3f2eSlogwang retval = rte_eth_rx_queue_setup(port, q, nb_rxd, 84a9643ea8Slogwang rte_eth_dev_socket_id(port), NULL, mbuf_pool); 85a9643ea8Slogwang if (retval < 0) 86a9643ea8Slogwang return retval; 87a9643ea8Slogwang } 88a9643ea8Slogwang 89a9643ea8Slogwang /* Allocate and set up 1 TX queue per Ethernet port. */ 90a9643ea8Slogwang for (q = 0; q < tx_rings; q++) { 91*2bfe3f2eSlogwang retval = rte_eth_tx_queue_setup(port, q, nb_txd, 92a9643ea8Slogwang rte_eth_dev_socket_id(port), NULL); 93a9643ea8Slogwang if (retval < 0) 94a9643ea8Slogwang return retval; 95a9643ea8Slogwang } 96a9643ea8Slogwang 97a9643ea8Slogwang /* Start the Ethernet port. */ 98a9643ea8Slogwang retval = rte_eth_dev_start(port); 99a9643ea8Slogwang if (retval < 0) 100a9643ea8Slogwang return retval; 101a9643ea8Slogwang 102a9643ea8Slogwang /* Display the port MAC address. */ 103a9643ea8Slogwang struct ether_addr addr; 104a9643ea8Slogwang rte_eth_macaddr_get(port, &addr); 105a9643ea8Slogwang printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8 106a9643ea8Slogwang " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n", 107*2bfe3f2eSlogwang port, 108a9643ea8Slogwang addr.addr_bytes[0], addr.addr_bytes[1], 109a9643ea8Slogwang addr.addr_bytes[2], addr.addr_bytes[3], 110a9643ea8Slogwang addr.addr_bytes[4], addr.addr_bytes[5]); 111a9643ea8Slogwang 112a9643ea8Slogwang /* Enable RX in promiscuous mode for the Ethernet device. */ 113a9643ea8Slogwang rte_eth_promiscuous_enable(port); 114a9643ea8Slogwang 115a9643ea8Slogwang return 0; 116a9643ea8Slogwang } 117a9643ea8Slogwang 118a9643ea8Slogwang /* 119a9643ea8Slogwang * The lcore main. This is the main thread that does the work, reading from 120a9643ea8Slogwang * an input port and writing to an output port. 121a9643ea8Slogwang */ 122a9643ea8Slogwang static __attribute__((noreturn)) void 123a9643ea8Slogwang lcore_main(void) 124a9643ea8Slogwang { 125*2bfe3f2eSlogwang const uint16_t nb_ports = rte_eth_dev_count(); 126*2bfe3f2eSlogwang uint16_t port; 127a9643ea8Slogwang 128a9643ea8Slogwang /* 129a9643ea8Slogwang * Check that the port is on the same NUMA node as the polling thread 130a9643ea8Slogwang * for best performance. 131a9643ea8Slogwang */ 132a9643ea8Slogwang for (port = 0; port < nb_ports; port++) 133a9643ea8Slogwang if (rte_eth_dev_socket_id(port) > 0 && 134a9643ea8Slogwang rte_eth_dev_socket_id(port) != 135a9643ea8Slogwang (int)rte_socket_id()) 136a9643ea8Slogwang printf("WARNING, port %u is on remote NUMA node to " 137a9643ea8Slogwang "polling thread.\n\tPerformance will " 138a9643ea8Slogwang "not be optimal.\n", port); 139a9643ea8Slogwang 140a9643ea8Slogwang printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n", 141a9643ea8Slogwang rte_lcore_id()); 142a9643ea8Slogwang 143a9643ea8Slogwang /* Run until the application is quit or killed. */ 144a9643ea8Slogwang for (;;) { 145a9643ea8Slogwang /* 146a9643ea8Slogwang * Receive packets on a port and forward them on the paired 147a9643ea8Slogwang * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc. 148a9643ea8Slogwang */ 149a9643ea8Slogwang for (port = 0; port < nb_ports; port++) { 150a9643ea8Slogwang 151a9643ea8Slogwang /* Get burst of RX packets, from first port of pair. */ 152a9643ea8Slogwang struct rte_mbuf *bufs[BURST_SIZE]; 153a9643ea8Slogwang const uint16_t nb_rx = rte_eth_rx_burst(port, 0, 154a9643ea8Slogwang bufs, BURST_SIZE); 155a9643ea8Slogwang 156a9643ea8Slogwang if (unlikely(nb_rx == 0)) 157a9643ea8Slogwang continue; 158a9643ea8Slogwang 159a9643ea8Slogwang /* Send burst of TX packets, to second port of pair. */ 160a9643ea8Slogwang const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0, 161a9643ea8Slogwang bufs, nb_rx); 162a9643ea8Slogwang 163a9643ea8Slogwang /* Free any unsent packets. */ 164a9643ea8Slogwang if (unlikely(nb_tx < nb_rx)) { 165a9643ea8Slogwang uint16_t buf; 166a9643ea8Slogwang for (buf = nb_tx; buf < nb_rx; buf++) 167a9643ea8Slogwang rte_pktmbuf_free(bufs[buf]); 168a9643ea8Slogwang } 169a9643ea8Slogwang } 170a9643ea8Slogwang } 171a9643ea8Slogwang } 172a9643ea8Slogwang 173a9643ea8Slogwang /* 174a9643ea8Slogwang * The main function, which does initialization and calls the per-lcore 175a9643ea8Slogwang * functions. 176a9643ea8Slogwang */ 177a9643ea8Slogwang int 178a9643ea8Slogwang main(int argc, char *argv[]) 179a9643ea8Slogwang { 180a9643ea8Slogwang struct rte_mempool *mbuf_pool; 181a9643ea8Slogwang unsigned nb_ports; 182*2bfe3f2eSlogwang uint16_t portid; 183a9643ea8Slogwang 184a9643ea8Slogwang /* Initialize the Environment Abstraction Layer (EAL). */ 185a9643ea8Slogwang int ret = rte_eal_init(argc, argv); 186a9643ea8Slogwang if (ret < 0) 187a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); 188a9643ea8Slogwang 189a9643ea8Slogwang argc -= ret; 190a9643ea8Slogwang argv += ret; 191a9643ea8Slogwang 192a9643ea8Slogwang /* Check that there is an even number of ports to send/receive on. */ 193a9643ea8Slogwang nb_ports = rte_eth_dev_count(); 194a9643ea8Slogwang if (nb_ports < 2 || (nb_ports & 1)) 195a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n"); 196a9643ea8Slogwang 197a9643ea8Slogwang /* Creates a new mempool in memory to hold the mbufs. */ 198a9643ea8Slogwang mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports, 199a9643ea8Slogwang MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); 200a9643ea8Slogwang 201a9643ea8Slogwang if (mbuf_pool == NULL) 202a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n"); 203a9643ea8Slogwang 204a9643ea8Slogwang /* Initialize all ports. */ 205a9643ea8Slogwang for (portid = 0; portid < nb_ports; portid++) 206a9643ea8Slogwang if (port_init(portid, mbuf_pool) != 0) 207*2bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu16 "\n", 208a9643ea8Slogwang portid); 209a9643ea8Slogwang 210a9643ea8Slogwang if (rte_lcore_count() > 1) 211a9643ea8Slogwang printf("\nWARNING: Too many lcores enabled. Only 1 used.\n"); 212a9643ea8Slogwang 213a9643ea8Slogwang /* Call lcore_main on the master core only. */ 214a9643ea8Slogwang lcore_main(); 215a9643ea8Slogwang 216a9643ea8Slogwang return 0; 217a9643ea8Slogwang } 218