xref: /dpdk/doc/guides/sample_app_ug/rxtx_callbacks.rst (revision 945acb4a0d644d194f1823084a234f9c286dcf8c)
1..  BSD LICENSE
2    Copyright(c) 2015 Intel Corporation. All rights reserved.
3    All rights reserved.
4
5    Redistribution and use in source and binary forms, with or without
6    modification, are permitted provided that the following conditions
7    are met:
8
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
14    distribution.
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.
18
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.
30
31
32RX/TX Callbacks Sample Application
33==================================
34
35The RX/TX Callbacks sample application is a packet forwarding application that
36demonstrates the use of user defined callbacks on received and transmitted
37packets. The application performs a simple latency check, using callbacks, to
38determine the time packets spend within the application.
39
40In the sample application a user defined callback is applied to all received
41packets to add a timestamp. A separate callback is applied to all packets
42prior to transmission to calculate the elapsed time, in CPU cycles.
43
44
45Compiling the Application
46-------------------------
47
48To compile the sample application see :doc:`compiling`.
49
50The application is located in the ``rxtx_callbacks`` sub-directory.
51
52The callbacks feature requires that the ``CONFIG_RTE_ETHDEV_RXTX_CALLBACKS``
53setting is on in the ``config/common_`` config file that applies to the
54target. This is generally on by default:
55
56.. code-block:: console
57
58    CONFIG_RTE_ETHDEV_RXTX_CALLBACKS=y
59
60Running the Application
61-----------------------
62
63To run the example in a ``linuxapp`` environment:
64
65.. code-block:: console
66
67    ./build/rxtx_callbacks -l 1 -n 4
68
69Refer to *DPDK Getting Started Guide* for general information on running
70applications and the Environment Abstraction Layer (EAL) options.
71
72
73
74Explanation
75-----------
76
77The ``rxtx_callbacks`` application is mainly a simple forwarding application
78based on the :doc:`skeleton`. See that section of the documentation for more
79details of the forwarding part of the application.
80
81The sections below explain the additional RX/TX callback code.
82
83
84The Main Function
85~~~~~~~~~~~~~~~~~
86
87The ``main()`` function performs the application initialization and calls the
88execution threads for each lcore. This function is effectively identical to
89the ``main()`` function explained in :doc:`skeleton`.
90
91The ``lcore_main()`` function is also identical.
92
93The main difference is in the user defined ``port_init()`` function where the
94callbacks are added. This is explained in the next section:
95
96
97The Port Initialization  Function
98~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
99
100The main functional part of the port initialization is shown below with
101comments:
102
103.. code-block:: c
104
105    static inline int
106    port_init(uint16_t port, struct rte_mempool *mbuf_pool)
107    {
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;
111        int retval;
112        uint16_t q;
113
114        if (port >= rte_eth_dev_count())
115            return -1;
116
117        /* Configure the Ethernet device. */
118        retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
119        if (retval != 0)
120            return retval;
121
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);
126            if (retval < 0)
127                return retval;
128        }
129
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);
134            if (retval < 0)
135                return retval;
136        }
137
138        /* Start the Ethernet port. */
139        retval = rte_eth_dev_start(port);
140        if (retval < 0)
141            return retval;
142
143        /* Enable RX in promiscuous mode for the Ethernet device. */
144        rte_eth_promiscuous_enable(port);
145
146
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);
150
151        return 0;
152    }
153
154
155The RX and TX callbacks are added to the ports/queues as function pointers:
156
157.. code-block:: c
158
159        rte_eth_add_rx_callback(port, 0, add_timestamps, NULL);
160        rte_eth_add_tx_callback(port, 0, calc_latency,   NULL);
161
162More than one callback can be added and additional information can be passed
163to callback function pointers as a ``void*``. In the examples above ``NULL``
164is used.
165
166The ``add_timestamps()`` and ``calc_latency()`` functions are explained below.
167
168
169The add_timestamps() Callback
170~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
171
172The ``add_timestamps()`` callback is added to the RX port and is applied to
173all packets received:
174
175.. code-block:: c
176
177    static uint16_t
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)
180    {
181        unsigned i;
182        uint64_t now = rte_rdtsc();
183
184        for (i = 0; i < nb_pkts; i++)
185            pkts[i]->udata64 = now;
186
187        return nb_pkts;
188    }
189
190The DPDK function ``rte_rdtsc()`` is used to add a cycle count timestamp to
191each packet (see the *cycles* section of the *DPDK API Documentation* for
192details).
193
194
195The calc_latency() Callback
196~~~~~~~~~~~~~~~~~~~~~~~~~~~
197
198The ``calc_latency()`` callback is added to the TX port and is applied to all
199packets prior to transmission:
200
201.. code-block:: c
202
203    static uint16_t
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)
206    {
207        uint64_t cycles = 0;
208        uint64_t now = rte_rdtsc();
209        unsigned i;
210
211        for (i = 0; i < nb_pkts; i++)
212            cycles += now - pkts[i]->udata64;
213
214        latency_numbers.total_cycles += cycles;
215        latency_numbers.total_pkts   += nb_pkts;
216
217        if (latency_numbers.total_pkts > (100 * 1000 * 1000ULL)) {
218            printf("Latency = %"PRIu64" cycles\n",
219                    latency_numbers.total_cycles / latency_numbers.total_pkts);
220
221            latency_numbers.total_cycles = latency_numbers.total_pkts = 0;
222        }
223
224        return nb_pkts;
225    }
226
227The ``calc_latency()`` function accumulates the total number of packets and
228the total number of cycles used. Once more than 100 million packets have been
229transmitted the average cycle count per packet is printed out and the counters
230are reset.
231