1 .. SPDX-License-Identifier: BSD-3-Clause
2 Copyright(c) 2015 Intel Corporation.
4 Basic Forwarding Sample Application
5 ===================================
7 The Basic Forwarding sample application is a simple *skeleton* example of a
8 forwarding application.
10 It is intended as a demonstration of the basic components of a DPDK forwarding
11 application. For more detailed implementations see the L2 and L3 forwarding
14 Compiling the Application
15 -------------------------
17 To compile the sample application see :doc:`compiling`.
19 The application is located in the ``skeleton`` sub-directory.
21 Running the Application
22 -----------------------
24 To run the example in a ``linuxapp`` environment:
26 .. code-block:: console
28 ./build/basicfwd -l 1 -n 4
30 Refer to *DPDK Getting Started Guide* for general information on running
31 applications and the Environment Abstraction Layer (EAL) options.
37 The following sections provide an explanation of the main components of the
40 All DPDK library functions used in the sample code are prefixed with ``rte_``
41 and are explained in detail in the *DPDK API Documentation*.
47 The ``main()`` function performs the initialization and calls the execution
48 threads for each lcore.
50 The first task is to initialize the Environment Abstraction Layer (EAL). The
51 ``argc`` and ``argv`` arguments are provided to the ``rte_eal_init()``
52 function. The value returned is the number of parsed arguments:
56 int ret = rte_eal_init(argc, argv);
58 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
61 The ``main()`` also allocates a mempool to hold the mbufs (Message Buffers)
62 used by the application:
66 mbuf_pool = rte_mempool_create("MBUF_POOL",
70 sizeof(struct rte_pktmbuf_pool_private),
71 rte_pktmbuf_pool_init, NULL,
72 rte_pktmbuf_init, NULL,
76 Mbufs are the packet buffer structure used by DPDK. They are explained in
77 detail in the "Mbuf Library" section of the *DPDK Programmer's Guide*.
79 The ``main()`` function also initializes all the ports using the user defined
80 ``port_init()`` function which is explained in the next section:
84 RTE_ETH_FOREACH_DEV(portid) {
85 if (port_init(portid, mbuf_pool) != 0) {
86 rte_exit(EXIT_FAILURE,
87 "Cannot init port %" PRIu8 "\n", portid);
92 Once the initialization is complete, the application is ready to launch a
93 function on an lcore. In this example ``lcore_main()`` is called on a single
101 The ``lcore_main()`` function is explained below.
105 The Port Initialization Function
106 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
108 The main functional part of the port initialization used in the Basic
109 Forwarding application is shown below:
114 port_init(uint16_t port, struct rte_mempool *mbuf_pool)
116 struct rte_eth_conf port_conf = port_conf_default;
117 const uint16_t rx_rings = 1, tx_rings = 1;
118 struct ether_addr addr;
122 if (port >= rte_eth_dev_count())
125 /* Configure the Ethernet device. */
126 retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
130 /* Allocate and set up 1 RX queue per Ethernet port. */
131 for (q = 0; q < rx_rings; q++) {
132 retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE,
133 rte_eth_dev_socket_id(port), NULL, mbuf_pool);
138 /* Allocate and set up 1 TX queue per Ethernet port. */
139 for (q = 0; q < tx_rings; q++) {
140 retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE,
141 rte_eth_dev_socket_id(port), NULL);
146 /* Start the Ethernet port. */
147 retval = rte_eth_dev_start(port);
151 /* Enable RX in promiscuous mode for the Ethernet device. */
152 rte_eth_promiscuous_enable(port);
157 The Ethernet ports are configured with default settings using the
158 ``rte_eth_dev_configure()`` function and the ``port_conf_default`` struct:
162 static const struct rte_eth_conf port_conf_default = {
163 .rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN }
166 For this example the ports are set up with 1 RX and 1 TX queue using the
167 ``rte_eth_rx_queue_setup()`` and ``rte_eth_tx_queue_setup()`` functions.
169 The Ethernet port is then started:
173 retval = rte_eth_dev_start(port);
176 Finally the RX port is set in promiscuous mode:
180 rte_eth_promiscuous_enable(port);
186 As we saw above the ``main()`` function calls an application function on the
187 available lcores. For the Basic Forwarding application the lcore function
188 looks like the following:
192 static __attribute__((noreturn)) void
195 const uint16_t nb_ports = rte_eth_dev_count();
199 * Check that the port is on the same NUMA node as the polling thread
200 * for best performance.
202 RTE_ETH_FOREACH_DEV(port)
203 if (rte_eth_dev_socket_id(port) > 0 &&
204 rte_eth_dev_socket_id(port) !=
205 (int)rte_socket_id())
206 printf("WARNING, port %u is on remote NUMA node to "
207 "polling thread.\n\tPerformance will "
208 "not be optimal.\n", port);
210 printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n",
213 /* Run until the application is quit or killed. */
216 * Receive packets on a port and forward them on the paired
217 * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
219 RTE_ETH_FOREACH_DEV(port) {
221 /* Get burst of RX packets, from first port of pair. */
222 struct rte_mbuf *bufs[BURST_SIZE];
223 const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
226 if (unlikely(nb_rx == 0))
229 /* Send burst of TX packets, to second port of pair. */
230 const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,
233 /* Free any unsent packets. */
234 if (unlikely(nb_tx < nb_rx)) {
236 for (buf = nb_tx; buf < nb_rx; buf++)
237 rte_pktmbuf_free(bufs[buf]);
244 The main work of the application is done within the loop:
249 RTE_ETH_FOREACH_DEV(port) {
251 /* Get burst of RX packets, from first port of pair. */
252 struct rte_mbuf *bufs[BURST_SIZE];
253 const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
256 if (unlikely(nb_rx == 0))
259 /* Send burst of TX packets, to second port of pair. */
260 const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,
263 /* Free any unsent packets. */
264 if (unlikely(nb_tx < nb_rx)) {
266 for (buf = nb_tx; buf < nb_rx; buf++)
267 rte_pktmbuf_free(bufs[buf]);
272 Packets are received in bursts on the RX ports and transmitted in bursts on
273 the TX ports. The ports are grouped in pairs with a simple mapping scheme
274 using the an XOR on the port number::
284 The ``rte_eth_tx_burst()`` function frees the memory buffers of packets that
285 are transmitted. If packets fail to transmit, ``(nb_tx < nb_rx)``, then they
286 must be freed explicitly using ``rte_pktmbuf_free()``.
288 The forwarding loop can be interrupted and the application closed using