doc: sample application user guide
[dpdk.git] / doc / guides / sample_app_ug / exception_path.rst
1 ..  BSD LICENSE
2     Copyright(c) 2010-2014 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 Exception Path Sample Application
32 =================================
33
34 The Exception Path sample application is a simple example that demonstrates the use of the Intel® DPDK
35 to set up an exception path for packets to go through the Linux* kernel.
36 This is done by using virtual TAP network interfaces.
37 These can be read from and written to by the Intel® DPDK application and
38 appear to the kernel as a standard network interface.
39
40 Overview
41 --------
42
43 The application creates two threads for each NIC port being used.
44 One thread reads from the port and writes the data unmodified to a thread-specific TAP interface.
45 The second thread reads from a TAP interface and writes the data unmodified to the NIC port.
46
47 The packet flow through the exception path application is as shown in the following figure.
48
49 .. _figure_1:
50
51 **Figure 1. Packet Flow**
52
53 .. image2_png has been replaced
54
55 |exception_path_example|
56
57 To make throughput measurements, kernel bridges must be setup to forward data between the bridges appropriately.
58
59 Compiling the Application
60 -------------------------
61
62 #.  Go to example directory:
63
64     .. code-block:: console
65
66         export RTE_SDK=/path/to/rte_sdk
67         cd ${RTE_SDK}/examples/exception_path
68
69 #.  Set the target (a default target will be used if not specified).
70     For example:
71
72     .. code-block:: console
73
74         export RTE_TARGET=x86_64-native-linuxapp-gcc
75
76 This application is intended as a linuxapp only.
77 See the *Intel® DPDK Getting Started Guide* for possible RTE_TARGET values.
78
79 #.  Build the application:
80
81     .. code-block:: console
82
83         make
84
85 Running the Application
86 -----------------------
87
88 The application requires a number of command line options:
89
90 .. code-block:: console
91
92     .build/exception_path [EAL options] -- -p PORTMASK -i IN_CORES -o OUT_CORES
93
94 where:
95
96 *   -p PORTMASK: A hex bitmask of ports to use
97
98 *   -i IN_CORES: A hex bitmask of cores which read from NIC
99
100 *   -o OUT_CORES: A hex bitmask of cores which write to NIC
101
102 Refer to the *Intel® DPDK Getting Started Guide* for general information on running applications
103 and the Environment Abstraction Layer (EAL) options.
104
105 The number of bits set in each bitmask must be the same.
106 The coremask -c parameter of the EAL options should include IN_CORES and OUT_CORES.
107 The same bit must not be set in IN_CORES and OUT_CORES.
108 The affinities between ports and cores are set beginning with the least significant bit of each mask, that is,
109 the port represented by the lowest bit in PORTMASK is read from by the core represented by the lowest bit in IN_CORES,
110 and written to by the core represented by the lowest bit in OUT_CORES.
111
112 For example to run the application with two ports and four cores:
113
114 .. code-block:: console
115
116     ./build/exception_path -c f -n 4 -- -p 3 -i 3 -o c
117
118 Getting Statistics
119 ~~~~~~~~~~~~~~~~~~
120
121 While the application is running, statistics on packets sent and
122 received can be displayed by sending the SIGUSR1 signal to the application from another terminal:
123
124 .. code-block:: console
125
126     killall -USR1 exception_path
127
128 The statistics can be reset by sending a SIGUSR2 signal in a similar way.
129
130 Explanation
131 -----------
132
133 The following sections provide some explanation of the code.
134
135 Initialization
136 ~~~~~~~~~~~~~~
137
138 Setup of the mbuf pool, driver and queues is similar to the setup done in the L2 Forwarding sample application
139 (see Chapter 9 "L2 forwarding Sample Application (in Real and Virtualized Environments" for details).
140 In addition, the TAP interfaces must also be created.
141 A TAP interface is created for each lcore that is being used.
142 The code for creating the TAP interface is as follows:
143
144 .. code-block:: c
145
146     /*
147      *   Create a tap network interface, or use existing one with same name.
148      *   If name[0]='\0' then a name is automatically assigned and returned in name.
149      */
150
151     static int tap_create(char *name)
152     {
153         struct ifreq ifr;
154         int fd, ret;
155
156         fd = open("/dev/net/tun", O_RDWR);
157         if (fd < 0)
158             return fd;
159
160         memset(&ifr, 0, sizeof(ifr));
161
162         /* TAP device without packet information */
163
164         ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
165         if (name && *name)
166             rte_snprinf(ifr.ifr_name, IFNAMSIZ, name);
167
168         ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
169
170         if (ret < 0) {
171             close(fd);
172             return ret;
173
174         }
175
176         if (name)
177             rte_snprintf(name, IFNAMSIZ, ifr.ifr_name);
178
179         return fd;
180     }
181
182 The other step in the initialization process that is unique to this sample application
183 is the association of each port with two cores:
184
185 *   One core to read from the port and write to a TAP interface
186
187 *   A second core to read from a TAP interface and write to the port
188
189 This is done using an array called port_ids[], which is indexed by the lcore IDs.
190 The population of this array is shown below:
191
192 .. code-block:: c
193
194     tx_port = 0;
195     rx_port = 0;
196
197     RTE_LCORE_FOREACH(i) {
198         if (input_cores_mask & (1ULL << i)) {
199             /* Skip ports that are not enabled */
200             while ((ports_mask & (1 << rx_port)) == 0) {
201                 rx_port++;
202                 if (rx_port > (sizeof(ports_mask) * 8))
203                     goto fail; /* not enough ports */
204             }
205             port_ids[i] = rx_port++;
206         } else if (output_cores_mask & (1ULL << i)) {
207             /* Skip ports that are not enabled */
208             while ((ports_mask & (1 << tx_port)) == 0) {
209                 tx_port++;
210                 if (tx_port > (sizeof(ports_mask) * 8))
211                    goto fail; /* not enough ports */
212             }
213             port_ids[i] = tx_port++;
214         }
215    }
216
217 Packet Forwarding
218 ~~~~~~~~~~~~~~~~~
219
220 After the initialization steps are complete, the main_loop() function is run on each lcore.
221 This function first checks the lcore_id against the user provided input_cores_mask and output_cores_mask to see
222 if this core is reading from or writing to a TAP interface.
223
224 For the case that reads from a NIC port, the packet reception is the same as in the L2 Forwarding sample application
225 (see Section 9.4.6, "Receive, Process and Transmit Packets").
226 The packet transmission is done by calling write() with the file descriptor of the appropriate TAP interface
227 and then explicitly freeing the mbuf back to the pool.
228
229 ..  code-block:: c
230
231     /* Loop forever reading from NIC and writing to tap */
232
233     for (;;) {
234         struct rte_mbuf *pkts_burst[PKT_BURST_SZ];
235         unsigned i;
236
237         const unsigned nb_rx = rte_eth_rx_burst(port_ids[lcore_id], 0, pkts_burst, PKT_BURST_SZ);
238
239         lcore_stats[lcore_id].rx += nb_rx;
240
241         for (i = 0; likely(i < nb_rx); i++) {
242             struct rte_mbuf *m = pkts_burst[i];
243             int ret = write(tap_fd, rte_pktmbuf_mtod(m, void*),
244
245             rte_pktmbuf_data_len(m));
246             rte_pktmbuf_free(m);
247             if (unlikely(ret<0))
248                 lcore_stats[lcore_id].dropped++;
249             else
250                 lcore_stats[lcore_id].tx++;
251         }
252     }
253
254 For the other case that reads from a TAP interface and writes to a NIC port,
255 packets are retrieved by doing a read() from the file descriptor of the appropriate TAP interface.
256 This fills in the data into the mbuf, then other fields are set manually.
257 The packet can then be transmitted as normal.
258
259 .. code-block:: c
260
261     /* Loop forever reading from tap and writing to NIC */
262
263     for (;;) {
264         int ret;
265         struct rte_mbuf *m = rte_pktmbuf_alloc(pktmbuf_pool);
266
267         if (m == NULL)
268             continue;
269
270         ret = read(tap_fd, m->pkt.data, MAX_PACKET_SZ); lcore_stats[lcore_id].rx++;
271         if (unlikely(ret < 0)) {
272             FATAL_ERROR("Reading from %s interface failed", tap_name);
273         }
274
275         m->pkt.nb_segs = 1;
276         m->pkt.next = NULL;
277         m->pkt.data_len = (uint16_t)ret;
278
279         ret = rte_eth_tx_burst(port_ids[lcore_id], 0, &m, 1);
280         if (unlikely(ret < 1)) {
281             rte_pktmuf_free(m);
282             lcore_stats[lcore_id].dropped++;
283         }
284         else {
285             lcore_stats[lcore_id].tx++;
286         }
287     }
288
289 To set up loops for measuring throughput, TAP interfaces can be connected using bridging.
290 The steps to do this are described in the section that follows.
291
292 Managing TAP Interfaces and Bridges
293 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
294
295 The Exception Path sample application creates TAP interfaces with names of the format tap_dpdk_nn,
296 where nn is the lcore ID. These TAP interfaces need to be configured for use:
297
298 .. code-block:: console
299
300     ifconfig tap_dpdk_00 up
301
302 To set up a bridge between two interfaces so that packets sent to one interface can be read from another,
303 use the brctl tool:
304
305 .. code-block:: console
306
307     brctl addbr "br0"
308     brctl addif br0 tap_dpdk_00
309     brctl addif br0 tap_dpdk_03
310     ifconfig br0 up
311
312 The TAP interfaces created by this application exist only when the application is running,
313 so the steps above need to be repeated each time the application is run.
314 To avoid this, persistent TAP interfaces can be created using openvpn:
315
316 .. code-block:: console
317
318     openvpn --mktun --dev tap_dpdk_00
319
320 If this method is used, then the steps above have to be done only once and
321 the same TAP interfaces can be reused each time the application is run.
322 To remove bridges and persistent TAP interfaces, the following commands are used:
323
324 .. code-block:: console
325
326     ifconfig br0 down
327     brctl delbr br0
328     openvpn --rmtun --dev tap_dpdk_00
329
330 .. |exception_path_example| image:: img/exception_path_example.svg