New upstream version 17.11-rc3
[deb_dpdk.git] / doc / guides / sample_app_ug / flow_filtering.rst
1 ..  BSD LICENSE
2     Copyright(c) 2017 Mellanox 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 Mellanox 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 Basic RTE Flow Filtering Sample Application
33 ===========================================
34
35 The Basic RTE flow filtering sample application is a simple example of a
36 creating a RTE flow rule.
37
38 It is intended as a demonstration of the basic components RTE flow rules.
39
40
41 Compiling the Application
42 -------------------------
43
44 To compile the application export the path to the DPDK source tree and go to
45 the example directory:
46
47 .. code-block:: console
48
49     export RTE_SDK=/path/to/rte_sdk
50
51     cd ${RTE_SDK}/examples/flow_filtering
52
53 Set the target, for example:
54
55 .. code-block:: console
56
57     export RTE_TARGET=x86_64-native-linuxapp-gcc
58
59 See the *DPDK Getting Started* Guide for possible ``RTE_TARGET`` values.
60
61 Build the application as follows:
62
63 .. code-block:: console
64
65     make
66
67
68 Running the Application
69 -----------------------
70
71 To run the example in a ``linuxapp`` environment:
72
73 .. code-block:: console
74
75     ./build/flow -l 1 -n 1
76
77 Refer to *DPDK Getting Started Guide* for general information on running
78 applications and the Environment Abstraction Layer (EAL) options.
79
80
81 Explanation
82 -----------
83
84 The example is build from 2 main files,
85 ``main.c`` which holds the example logic and ``flow_blocks.c`` that holds the
86 implementation for building the flow rule.
87
88 The following sections provide an explanation of the main components of the
89 code.
90
91 All DPDK library functions used in the sample code are prefixed with ``rte_``
92 and are explained in detail in the *DPDK API Documentation*.
93
94
95 The Main Function
96 ~~~~~~~~~~~~~~~~~
97
98 The ``main()`` function located in ``main.c`` file performs the initialization
99 and runs the main loop function.
100
101 The first task is to initialize the Environment Abstraction Layer (EAL).  The
102 ``argc`` and ``argv`` arguments are provided to the ``rte_eal_init()``
103 function. The value returned is the number of parsed arguments:
104
105 .. code-block:: c
106
107     int ret = rte_eal_init(argc, argv);
108     if (ret < 0)
109         rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
110
111
112 The ``main()`` also allocates a mempool to hold the mbufs (Message Buffers)
113 used by the application:
114
115 .. code-block:: c
116
117    mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", 4096, 128, 0,
118                                             RTE_MBUF_DEFAULT_BUF_SIZE,
119                                             rte_socket_id());
120
121 Mbufs are the packet buffer structure used by DPDK. They are explained in
122 detail in the "Mbuf Library" section of the *DPDK Programmer's Guide*.
123
124 The ``main()`` function also initializes all the ports using the user defined
125 ``init_port()`` function which is explained in the next section:
126
127 .. code-block:: c
128
129    init_port();
130
131 Once the initialization is complete, we set the flow rule using the
132 following code:
133
134 .. code-block:: c
135
136    /* create flow for send packet with */
137    flow = generate_ipv4_flow(port_id, selected_queue,
138                                 SRC_IP, EMPTY_MASK,
139                                 DEST_IP, FULL_MASK, &error);
140    if (!flow) {
141           printf("Flow can't be created %d message: %s\n",
142                        error.type,
143                        error.message ? error.message : "(no stated reason)");
144           rte_exit(EXIT_FAILURE, "error in creating flow");
145    }
146
147 In the last part the application is ready to launch the
148 ``main_loop()`` function. Which is explained below.
149
150
151 .. code-block:: c
152
153    main_loop();
154
155 The Port Initialization  Function
156 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
157
158 The main functional part of the port initialization used in the flow filtering
159 application is shown below:
160
161 .. code-block:: c
162
163    init_port(void)
164    {
165            int ret;
166            uint16_t i;
167            struct rte_eth_conf port_conf = {
168                    .rxmode = {
169                            .split_hdr_size = 0,
170                            /**< Header Split disabled */
171                            .header_split   = 0,
172                            /**< IP checksum offload disabled */
173                            .hw_ip_checksum = 0,
174                            /**< VLAN filtering disabled */
175                            .hw_vlan_filter = 0,
176                            /**< Jumbo Frame Support disabled */
177                            .jumbo_frame    = 0,
178                            /**< CRC stripped by hardware */
179                            .hw_strip_crc   = 1,
180                    },
181            };
182
183            printf(":: initializing port: %d\n", port_id);
184            ret = rte_eth_dev_configure(port_id,
185                                    nr_queues, nr_queues, &port_conf);
186            if (ret < 0) {
187                    rte_exit(EXIT_FAILURE,
188                            ":: cannot configure device: err=%d, port=%u\n",
189                            ret, port_id);
190            }
191
192            /* only set Rx queues: something we care only so far */
193            for (i = 0; i < nr_queues; i++) {
194                    ret = rte_eth_rx_queue_setup(port_id, i, 512,
195                                         rte_eth_dev_socket_id(port_id),
196                                         NULL,
197                                         mbuf_pool);
198                    if (ret < 0) {
199                            rte_exit(EXIT_FAILURE,
200                               ":: Rx queue setup failed: err=%d, port=%u\n",
201                               ret, port_id);
202                    }
203            }
204
205
206            rte_eth_promiscuous_enable(port_id);
207
208            ret = rte_eth_dev_start(port_id);
209            if (ret < 0) {
210                    rte_exit(EXIT_FAILURE,
211                            "rte_eth_dev_start:err=%d, port=%u\n",
212                            ret, port_id);
213            }
214
215            assert_link_status();
216
217            printf(":: initializing port: %d done\n", port_id);
218    }
219
220 The Ethernet port is configured with default settings using the
221 ``rte_eth_dev_configure()`` function and the ``port_conf_default`` struct:
222
223 .. code-block:: c
224
225    struct rte_eth_conf port_conf = {
226                 .rxmode = {
227                         .split_hdr_size = 0,
228                         /**< Header Split disabled */
229                         .header_split   = 0,
230                         /**< IP checksum offload disabled */
231                         .hw_ip_checksum = 0,
232                         /**< VLAN filtering disabled */
233                         .hw_vlan_filter = 0,
234                         /**< Jumbo Frame Support disabled */
235                         .jumbo_frame    = 0,
236                         /**< CRC stripped by hardware */
237                         .hw_strip_crc   = 1,
238                 },
239    };
240
241    ret = rte_eth_dev_configure(port_id, nr_queues, nr_queues, &port_conf);
242    if (ret < 0) {
243         rte_exit(EXIT_FAILURE,
244                  ":: cannot configure device: err=%d, port=%u\n",
245                  ret, port_id);
246    }
247
248 For this example we are configuring number of rx queues that are connected to
249 a single port.
250
251 .. code-block:: c
252
253    for (i = 0; i < nr_queues; i++) {
254           ret = rte_eth_rx_queue_setup(port_id, i, 512,
255                                        rte_eth_dev_socket_id(port_id),
256                                        NULL,
257                                        mbuf_pool);
258           if (ret < 0) {
259                   rte_exit(EXIT_FAILURE,
260                           ":: Rx queue setup failed: err=%d, port=%u\n",
261                           ret, port_id);
262           }
263   }
264
265 In the next step we create and apply the flow rule. which is to send packets
266 with destination ip equals to 192.168.1.1 to queue number 1. The detail
267 explanation of the ``generate_ipv4_flow()`` appears later in this document:
268
269 .. code-block:: c
270
271    flow = generate_ipv4_flow(port_id, selected_queue,
272                              SRC_IP, EMPTY_MASK,
273                              DEST_IP, FULL_MASK, &error);
274
275 We are setting the RX port to promiscuous mode:
276
277 .. code-block:: c
278
279    rte_eth_promiscuous_enable(port_id);
280
281 The last step is to start the port.
282
283 .. code-block:: c
284
285    ret = rte_eth_dev_start(port_id);
286    if (ret < 0)  {
287         rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err%d, port=%u\n",
288                         ret, port_id);
289    }
290
291
292 The main_loop function
293 ~~~~~~~~~~~~~~~~~~~~~~
294
295 As we saw above the ``main()`` function calls an application function to handle
296 the main loop. For the flow filtering application the main_loop function
297 looks like the following:
298
299 .. code-block:: c
300
301    static void
302    main_loop(void)
303    {
304            struct rte_mbuf *mbufs[32];
305            struct ether_hdr *eth_hdr;
306            uint16_t nb_rx;
307            uint16_t i;
308            uint16_t j;
309
310            while (!force_quit) {
311                    for (i = 0; i < nr_queues; i++) {
312                            nb_rx = rte_eth_rx_burst(port_id,
313                                                    i, mbufs, 32);
314                            if (nb_rx) {
315                                    for (j = 0; j < nb_rx; j++) {
316                                            struct rte_mbuf *m = mbufs[j];
317
318                                            eth_hdr = rte_pktmbuf_mtod(m,
319                                                         struct ether_hdr *);
320                                            print_ether_addr("src=",
321                                                         &eth_hdr->s_addr);
322                                            print_ether_addr(" - dst=",
323                                                         &eth_hdr->d_addr);
324                                            printf(" - queue=0x%x",
325                                                            (unsigned int)i);
326                                            printf("\n");
327                                            rte_pktmbuf_free(m);
328                                    }
329                            }
330                    }
331            }
332            /* closing and releasing resources */
333            rte_flow_flush(port_id, &error);
334            rte_eth_dev_stop(port_id);
335            rte_eth_dev_close(port_id);
336    }
337
338 The main work of the application is reading the packets from all
339 queues and printing for each packet the destination queue:
340
341 .. code-block:: c
342
343     while (!force_quit) {
344         for (i = 0; i < nr_queues; i++) {
345                    nb_rx = rte_eth_rx_burst(port_id, i, mbufs, 32);
346                 if (nb_rx) {
347                         for (j = 0; j < nb_rx; j++) {
348                              struct rte_mbuf *m = mbufs[j];
349                              eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
350                              print_ether_addr("src=", &eth_hdr->s_addr);
351                              print_ether_addr(" - dst=", &eth_hdr->d_addr);
352                              printf(" - queue=0x%x", (unsigned int)i);
353                              printf("\n");
354                              rte_pktmbuf_free(m);
355                         }
356                 }
357            }
358     }
359
360
361 The forwarding loop can be interrupted and the application closed using
362 ``Ctrl-C``. Which results in closing the port and the device using
363 ``rte_eth_dev_stop`` and ``rte_eth_dev_close``
364
365 The generate_ipv4_flow function
366 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
367
368 The generate_ipv4_rule function is responsible for creating the flow rule.
369 This function is located in the ``flow_blocks.c`` file.
370
371 .. code-block:: c
372
373    static struct rte_flow *
374    generate_ipv4_flow(uint8_t port_id, uint16_t rx_q,
375                    uint32_t src_ip, uint32_t src_mask,
376                    uint32_t dest_ip, uint32_t dest_mask,
377                    struct rte_flow_error *error)
378    {
379            struct rte_flow_attr attr;
380            struct rte_flow_item pattern[MAX_PATTERN_NUM];
381            struct rte_flow_action action[MAX_PATTERN_NUM];
382            struct rte_flow *flow = NULL;
383            struct rte_flow_action_queue queue = { .index = rx_q };
384            struct rte_flow_item_eth eth_spec;
385            struct rte_flow_item_eth eth_mask;
386            struct rte_flow_item_vlan vlan_spec;
387            struct rte_flow_item_vlan vlan_mask;
388            struct rte_flow_item_ipv4 ip_spec;
389            struct rte_flow_item_ipv4 ip_mask;
390
391            memset(pattern, 0, sizeof(pattern));
392            memset(action, 0, sizeof(action));
393
394            /*
395             * set the rule attribute.
396             * in this case only ingress packets will be checked.
397             */
398            memset(&attr, 0, sizeof(struct rte_flow_attr));
399            attr.ingress = 1;
400
401            /*
402             * create the action sequence.
403             * one action only,  move packet to queue
404             */
405
406            action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
407            action[0].conf = &queue;
408            action[1].type = RTE_FLOW_ACTION_TYPE_END;
409
410            /*
411             * set the first level of the pattern (eth).
412             * since in this example we just want to get the
413             * ipv4 we set this level to allow all.
414             */
415            memset(&eth_spec, 0, sizeof(struct rte_flow_item_eth));
416            memset(&eth_mask, 0, sizeof(struct rte_flow_item_eth));
417            eth_spec.type = 0;
418            eth_mask.type = 0;
419            pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
420            pattern[0].spec = &eth_spec;
421            pattern[0].mask = &eth_mask;
422
423            /*
424             * setting the second level of the pattern (vlan).
425             * since in this example we just want to get the
426             * ipv4 we also set this level to allow all.
427             */
428            memset(&vlan_spec, 0, sizeof(struct rte_flow_item_vlan));
429            memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
430            pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
431            pattern[1].spec = &vlan_spec;
432            pattern[1].mask = &vlan_mask;
433
434            /*
435             * setting the third level of the pattern (ip).
436             * in this example this is the level we care about
437             * so we set it according to the parameters.
438             */
439            memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4));
440            memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4));
441            ip_spec.hdr.dst_addr = htonl(dest_ip);
442            ip_mask.hdr.dst_addr = dest_mask;
443            ip_spec.hdr.src_addr = htonl(src_ip);
444            ip_mask.hdr.src_addr = src_mask;
445            pattern[2].type = RTE_FLOW_ITEM_TYPE_IPV4;
446            pattern[2].spec = &ip_spec;
447            pattern[2].mask = &ip_mask;
448
449            /* the final level must be always type end */
450            pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
451
452            int res = rte_flow_validate(port_id, &attr, pattern, action, error);
453            if(!res)
454                flow = rte_flow_create(port_id, &attr, pattern, action, error);
455
456            return flow;
457    }
458
459 The first part of the function is declaring the structures that will be used.
460
461 .. code-block:: c
462
463    struct rte_flow_attr attr;
464    struct rte_flow_item pattern[MAX_PATTERN_NUM];
465    struct rte_flow_action action[MAX_PATTERN_NUM];
466    struct rte_flow *flow;
467    struct rte_flow_error error;
468    struct rte_flow_action_queue queue = { .index = rx_q };
469    struct rte_flow_item_eth eth_spec;
470    struct rte_flow_item_eth eth_mask;
471    struct rte_flow_item_vlan vlan_spec;
472    struct rte_flow_item_vlan vlan_mask;
473    struct rte_flow_item_ipv4 ip_spec;
474    struct rte_flow_item_ipv4 ip_mask;
475
476 The following part create the flow attributes, in our case ingress.
477
478 .. code-block:: c
479
480    memset(&attr, 0, sizeof(struct rte_flow_attr));
481    attr.ingress = 1;
482
483 The third part defines the action to be taken when a packet matches
484 the rule. In this case send the packet to queue.
485
486 .. code-block:: c
487
488    action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
489    action[0].conf = &queue;
490    action[1].type = RTE_FLOW_ACTION_TYPE_END;
491
492 The forth part is responsible for creating the pattern and is build from
493 number of step. In each step we build one level of the pattern starting with
494 the lowest one.
495
496 Setting the first level of the pattern ETH:
497
498 .. code-block:: c
499
500    memset(&eth_spec, 0, sizeof(struct rte_flow_item_eth));
501    memset(&eth_mask, 0, sizeof(struct rte_flow_item_eth));
502    eth_spec.type = 0;
503    eth_mask.type = 0;
504    pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
505    pattern[0].spec = &eth_spec;
506    pattern[0].mask = &eth_mask;
507
508 Setting the second level of the pattern VLAN:
509
510 .. code-block:: c
511
512    memset(&vlan_spec, 0, sizeof(struct rte_flow_item_vlan));
513    memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
514    pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
515    pattern[1].spec = &vlan_spec;
516    pattern[1].mask = &vlan_mask;
517
518 Setting the third level ip:
519
520 .. code-block:: c
521
522    memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4));
523    memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4));
524    ip_spec.hdr.dst_addr = htonl(dest_ip);
525    ip_mask.hdr.dst_addr = dest_mask;
526    ip_spec.hdr.src_addr = htonl(src_ip);
527    ip_mask.hdr.src_addr = src_mask;
528    pattern[2].type = RTE_FLOW_ITEM_TYPE_IPV4;
529    pattern[2].spec = &ip_spec;
530    pattern[2].mask = &ip_mask;
531
532 Closing the pattern part.
533
534 .. code-block:: c
535
536    pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
537
538 The last part of the function is to validate the rule and create it.
539
540 .. code-block:: c
541
542    int res = rte_flow_validate(port_id, &attr, pattern, action, &error);
543    if (!res)
544         flow = rte_flow_create(port_id, &attr, pattern, action, &error);
545