2 Copyright(c) 2015 Intel Corporation. All rights reserved.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in
13 the documentation and/or other materials provided with the
15 * Neither the name of Intel Corporation nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 RX/TX Callbacks Sample Application
33 ==================================
35 The RX/TX Callbacks sample application is a packet forwarding application that
36 demonstrates the use of user defined callbacks on received and transmitted
37 packets. The application performs a simple latency check, using callbacks, to
38 determine the time packets spend within the application.
40 In the sample application a user defined callback is applied to all received
41 packets to add a timestamp. A separate callback is applied to all packets
42 prior to transmission to calculate the elapsed time, in CPU cycles.
45 Compiling the Application
46 -------------------------
48 To compile the sample application see :doc:`compiling`.
50 The application is located in the ``rxtx_callbacks`` sub-directory.
52 The callbacks feature requires that the ``CONFIG_RTE_ETHDEV_RXTX_CALLBACKS``
53 setting is on in the ``config/common_`` config file that applies to the
54 target. This is generally on by default:
56 .. code-block:: console
58 CONFIG_RTE_ETHDEV_RXTX_CALLBACKS=y
60 Running the Application
61 -----------------------
63 To run the example in a ``linuxapp`` environment:
65 .. code-block:: console
67 ./build/rxtx_callbacks -l 1 -n 4
69 Refer to *DPDK Getting Started Guide* for general information on running
70 applications and the Environment Abstraction Layer (EAL) options.
77 The ``rxtx_callbacks`` application is mainly a simple forwarding application
78 based on the :doc:`skeleton`. See that section of the documentation for more
79 details of the forwarding part of the application.
81 The sections below explain the additional RX/TX callback code.
87 The ``main()`` function performs the application initialization and calls the
88 execution threads for each lcore. This function is effectively identical to
89 the ``main()`` function explained in :doc:`skeleton`.
91 The ``lcore_main()`` function is also identical.
93 The main difference is in the user defined ``port_init()`` function where the
94 callbacks are added. This is explained in the next section:
97 The Port Initialization Function
98 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
100 The main functional part of the port initialization is shown below with
106 port_init(uint16_t port, struct rte_mempool *mbuf_pool)
108 struct rte_eth_conf port_conf = port_conf_default;
109 const uint16_t rx_rings = 1, tx_rings = 1;
110 struct ether_addr addr;
114 if (port >= rte_eth_dev_count())
117 /* Configure the Ethernet device. */
118 retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
122 /* Allocate and set up 1 RX queue per Ethernet port. */
123 for (q = 0; q < rx_rings; q++) {
124 retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE,
125 rte_eth_dev_socket_id(port), NULL, mbuf_pool);
130 /* Allocate and set up 1 TX queue per Ethernet port. */
131 for (q = 0; q < tx_rings; q++) {
132 retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE,
133 rte_eth_dev_socket_id(port), NULL);
138 /* Start the Ethernet port. */
139 retval = rte_eth_dev_start(port);
143 /* Enable RX in promiscuous mode for the Ethernet device. */
144 rte_eth_promiscuous_enable(port);
147 /* Add the callbacks for RX and TX.*/
148 rte_eth_add_rx_callback(port, 0, add_timestamps, NULL);
149 rte_eth_add_tx_callback(port, 0, calc_latency, NULL);
155 The RX and TX callbacks are added to the ports/queues as function pointers:
159 rte_eth_add_rx_callback(port, 0, add_timestamps, NULL);
160 rte_eth_add_tx_callback(port, 0, calc_latency, NULL);
162 More than one callback can be added and additional information can be passed
163 to callback function pointers as a ``void*``. In the examples above ``NULL``
166 The ``add_timestamps()`` and ``calc_latency()`` functions are explained below.
169 The add_timestamps() Callback
170 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
172 The ``add_timestamps()`` callback is added to the RX port and is applied to
173 all packets received:
178 add_timestamps(uint16_t port __rte_unused, uint16_t qidx __rte_unused,
179 struct rte_mbuf **pkts, uint16_t nb_pkts, void *_ __rte_unused)
182 uint64_t now = rte_rdtsc();
184 for (i = 0; i < nb_pkts; i++)
185 pkts[i]->udata64 = now;
190 The DPDK function ``rte_rdtsc()`` is used to add a cycle count timestamp to
191 each packet (see the *cycles* section of the *DPDK API Documentation* for
195 The calc_latency() Callback
196 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
198 The ``calc_latency()`` callback is added to the TX port and is applied to all
199 packets prior to transmission:
204 calc_latency(uint16_t port __rte_unused, uint16_t qidx __rte_unused,
205 struct rte_mbuf **pkts, uint16_t nb_pkts, void *_ __rte_unused)
208 uint64_t now = rte_rdtsc();
211 for (i = 0; i < nb_pkts; i++)
212 cycles += now - pkts[i]->udata64;
214 latency_numbers.total_cycles += cycles;
215 latency_numbers.total_pkts += nb_pkts;
217 if (latency_numbers.total_pkts > (100 * 1000 * 1000ULL)) {
218 printf("Latency = %"PRIu64" cycles\n",
219 latency_numbers.total_cycles / latency_numbers.total_pkts);
221 latency_numbers.total_cycles = latency_numbers.total_pkts = 0;
227 The ``calc_latency()`` function accumulates the total number of packets and
228 the total number of cycles used. Once more than 100 million packets have been
229 transmitted the average cycle count per packet is printed out and the counters