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