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