8d1bb86f7712929c0e74872e395eac45fbaa621b
[deb_dpdk.git] / doc / guides / sample_app_ug / rxtx_callbacks.rst
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
32 RX/TX Callbacks Sample Application
33 ==================================
34
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.
39
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.
43
44
45 Compiling the Application
46 -------------------------
47
48 To compile the application export the path to the DPDK source tree and go to
49 the example directory:
50
51 .. code-block:: console
52
53     export RTE_SDK=/path/to/rte_sdk
54
55     cd ${RTE_SDK}/examples/rxtx_callbacks
56
57
58 Set the target, for example:
59
60 .. code-block:: console
61
62     export RTE_TARGET=x86_64-native-linuxapp-gcc
63
64 See the *DPDK Getting Started* Guide for possible ``RTE_TARGET`` values.
65
66 The callbacks feature requires that the ``CONFIG_RTE_ETHDEV_RXTX_CALLBACKS``
67 setting is on in the ``config/common_`` config file that applies to the
68 target. This is generally on by default:
69
70 .. code-block:: console
71
72     CONFIG_RTE_ETHDEV_RXTX_CALLBACKS=y
73
74 Build the application as follows:
75
76 .. code-block:: console
77
78     make
79
80
81 Running the Application
82 -----------------------
83
84 To run the example in a ``linuxapp`` environment:
85
86 .. code-block:: console
87
88     ./build/rxtx_callbacks -l 1 -n 4
89
90 Refer to *DPDK Getting Started Guide* for general information on running
91 applications and the Environment Abstraction Layer (EAL) options.
92
93
94
95 Explanation
96 -----------
97
98 The ``rxtx_callbacks`` application is mainly a simple forwarding application
99 based on the :doc:`skeleton`. See that section of the documentation for more
100 details of the forwarding part of the application.
101
102 The sections below explain the additional RX/TX callback code.
103
104
105 The Main Function
106 ~~~~~~~~~~~~~~~~~
107
108 The ``main()`` function performs the application initialization and calls the
109 execution threads for each lcore. This function is effectively identical to
110 the ``main()`` function explained in :doc:`skeleton`.
111
112 The ``lcore_main()`` function is also identical.
113
114 The main difference is in the user defined ``port_init()`` function where the
115 callbacks are added. This is explained in the next section:
116
117
118 The Port Initialization  Function
119 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
120
121 The main functional part of the port initialization is shown below with
122 comments:
123
124 .. code-block:: c
125
126     static inline int
127     port_init(uint8_t port, struct rte_mempool *mbuf_pool)
128     {
129         struct rte_eth_conf port_conf = port_conf_default;
130         const uint16_t rx_rings = 1, tx_rings = 1;
131         struct ether_addr addr;
132         int retval;
133         uint16_t q;
134
135         if (port >= rte_eth_dev_count())
136             return -1;
137
138         /* Configure the Ethernet device. */
139         retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
140         if (retval != 0)
141             return retval;
142
143         /* Allocate and set up 1 RX queue per Ethernet port. */
144         for (q = 0; q < rx_rings; q++) {
145             retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE,
146                     rte_eth_dev_socket_id(port), NULL, mbuf_pool);
147             if (retval < 0)
148                 return retval;
149         }
150
151         /* Allocate and set up 1 TX queue per Ethernet port. */
152         for (q = 0; q < tx_rings; q++) {
153             retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE,
154                     rte_eth_dev_socket_id(port), NULL);
155             if (retval < 0)
156                 return retval;
157         }
158
159         /* Start the Ethernet port. */
160         retval = rte_eth_dev_start(port);
161         if (retval < 0)
162             return retval;
163
164         /* Enable RX in promiscuous mode for the Ethernet device. */
165         rte_eth_promiscuous_enable(port);
166
167
168         /* Add the callbacks for RX and TX.*/
169         rte_eth_add_rx_callback(port, 0, add_timestamps, NULL);
170         rte_eth_add_tx_callback(port, 0, calc_latency, NULL);
171
172         return 0;
173     }
174
175
176 The RX and TX callbacks are added to the ports/queues as function pointers:
177
178 .. code-block:: c
179
180         rte_eth_add_rx_callback(port, 0, add_timestamps, NULL);
181         rte_eth_add_tx_callback(port, 0, calc_latency,   NULL);
182
183 More than one callback can be added and additional information can be passed
184 to callback function pointers as a ``void*``. In the examples above ``NULL``
185 is used.
186
187 The ``add_timestamps()`` and ``calc_latency()`` functions are explained below.
188
189
190 The add_timestamps() Callback
191 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
192
193 The ``add_timestamps()`` callback is added to the RX port and is applied to
194 all packets received:
195
196 .. code-block:: c
197
198     static uint16_t
199     add_timestamps(uint8_t port __rte_unused, uint16_t qidx __rte_unused,
200             struct rte_mbuf **pkts, uint16_t nb_pkts, void *_ __rte_unused)
201     {
202         unsigned i;
203         uint64_t now = rte_rdtsc();
204
205         for (i = 0; i < nb_pkts; i++)
206             pkts[i]->udata64 = now;
207
208         return nb_pkts;
209     }
210
211 The DPDK function ``rte_rdtsc()`` is used to add a cycle count timestamp to
212 each packet (see the *cycles* section of the *DPDK API Documentation* for
213 details).
214
215
216 The calc_latency() Callback
217 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
218
219 The ``calc_latency()`` callback is added to the TX port and is applied to all
220 packets prior to transmission:
221
222 .. code-block:: c
223
224     static uint16_t
225     calc_latency(uint8_t port __rte_unused, uint16_t qidx __rte_unused,
226             struct rte_mbuf **pkts, uint16_t nb_pkts, void *_ __rte_unused)
227     {
228         uint64_t cycles = 0;
229         uint64_t now = rte_rdtsc();
230         unsigned i;
231
232         for (i = 0; i < nb_pkts; i++)
233             cycles += now - pkts[i]->udata64;
234
235         latency_numbers.total_cycles += cycles;
236         latency_numbers.total_pkts   += nb_pkts;
237
238         if (latency_numbers.total_pkts > (100 * 1000 * 1000ULL)) {
239             printf("Latency = %"PRIu64" cycles\n",
240                     latency_numbers.total_cycles / latency_numbers.total_pkts);
241
242             latency_numbers.total_cycles = latency_numbers.total_pkts = 0;
243         }
244
245         return nb_pkts;
246     }
247
248 The ``calc_latency()`` function accumulates the total number of packets and
249 the total number of cycles used. Once more than 100 million packets have been
250 transmitted the average cycle count per packet is printed out and the counters
251 are reset.