New upstream version 18.08
[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                            .offloads = DEV_RX_OFFLOAD_CRC_STRIP,
143                            },
144                    .txmode = {
145                            .offloads =
146                                    DEV_TX_OFFLOAD_VLAN_INSERT |
147                                    DEV_TX_OFFLOAD_IPV4_CKSUM  |
148                                    DEV_TX_OFFLOAD_UDP_CKSUM   |
149                                    DEV_TX_OFFLOAD_TCP_CKSUM   |
150                                    DEV_TX_OFFLOAD_SCTP_CKSUM  |
151                                    DEV_TX_OFFLOAD_TCP_TSO,
152                    },
153            };
154            struct rte_eth_txconf txq_conf;
155            struct rte_eth_rxconf rxq_conf;
156            struct rte_eth_dev_info dev_info;
157
158            printf(":: initializing port: %d\n", port_id);
159            ret = rte_eth_dev_configure(port_id,
160                    nr_queues, nr_queues, &port_conf);
161            if (ret < 0) {
162                    rte_exit(EXIT_FAILURE,
163                            ":: cannot configure device: err=%d, port=%u\n",
164                            ret, port_id);
165            }
166
167            rte_eth_dev_info_get(port_id, &dev_info);
168            rxq_conf = dev_info.default_rxconf;
169            rxq_conf.offloads = port_conf.rxmode.offloads;
170            /* only set Rx queues: something we care only so far */
171            for (i = 0; i < nr_queues; i++) {
172                    ret = rte_eth_rx_queue_setup(port_id, i, 512,
173                            rte_eth_dev_socket_id(port_id),
174                            &rxq_conf,
175                            mbuf_pool);
176                    if (ret < 0) {
177                             rte_exit(EXIT_FAILURE,
178                                     ":: Rx queue setup failed: err=%d, port=%u\n",
179                                     ret, port_id);
180                    }
181            }
182
183            txq_conf = dev_info.default_txconf;
184            txq_conf.offloads = port_conf.txmode.offloads;
185
186            for (i = 0; i < nr_queues; i++) {
187                    ret = rte_eth_tx_queue_setup(port_id, i, 512,
188                            rte_eth_dev_socket_id(port_id),
189                            &txq_conf);
190                    if (ret < 0) {
191                            rte_exit(EXIT_FAILURE,
192                                    ":: Tx queue setup failed: err=%d, port=%u\n",
193                                    ret, port_id);
194                    }
195           }
196
197            rte_eth_promiscuous_enable(port_id);
198            ret = rte_eth_dev_start(port_id);
199            if (ret < 0) {
200                    rte_exit(EXIT_FAILURE,
201                            "rte_eth_dev_start:err=%d, port=%u\n",
202                            ret, port_id);
203            }
204
205            assert_link_status();
206
207            printf(":: initializing port: %d done\n", port_id);
208    }
209
210 The Ethernet port is configured with default settings using the
211 ``rte_eth_dev_configure()`` function and the ``port_conf_default`` struct:
212
213 .. code-block:: c
214
215    struct rte_eth_conf port_conf = {
216            .rxmode = {
217                    .split_hdr_size = 0,
218                    .offloads = DEV_RX_OFFLOAD_CRC_STRIP,
219                    },
220            .txmode = {
221                    .offloads =
222                            DEV_TX_OFFLOAD_VLAN_INSERT |
223                            DEV_TX_OFFLOAD_IPV4_CKSUM  |
224                            DEV_TX_OFFLOAD_UDP_CKSUM   |
225                            DEV_TX_OFFLOAD_TCP_CKSUM   |
226                            DEV_TX_OFFLOAD_SCTP_CKSUM  |
227                            DEV_TX_OFFLOAD_TCP_TSO,
228                    },
229            };
230
231    ret = rte_eth_dev_configure(port_id, nr_queues, nr_queues, &port_conf);
232    if (ret < 0) {
233         rte_exit(EXIT_FAILURE,
234                  ":: cannot configure device: err=%d, port=%u\n",
235                  ret, port_id);
236    }
237    rte_eth_dev_info_get(port_id, &dev_info);
238    rxq_conf = dev_info.default_rxconf;
239    rxq_conf.offloads = port_conf.rxmode.offloads;
240
241 For this example we are configuring number of rx and tx queues that are connected
242 to a single port.
243
244 .. code-block:: c
245
246    for (i = 0; i < nr_queues; i++) {
247           ret = rte_eth_rx_queue_setup(port_id, i, 512,
248                                        rte_eth_dev_socket_id(port_id),
249                                        &rxq_conf,
250                                        mbuf_pool);
251           if (ret < 0) {
252                   rte_exit(EXIT_FAILURE,
253                           ":: Rx queue setup failed: err=%d, port=%u\n",
254                           ret, port_id);
255           }
256    }
257
258    for (i = 0; i < nr_queues; i++) {
259           ret = rte_eth_tx_queue_setup(port_id, i, 512,
260                                        rte_eth_dev_socket_id(port_id),
261                                        &txq_conf);
262           if (ret < 0) {
263                   rte_exit(EXIT_FAILURE,
264                            ":: Tx queue setup failed: err=%d, port=%u\n",
265                            ret, port_id);
266           }
267    }
268
269 In the next step we create and apply the flow rule. which is to send packets
270 with destination ip equals to 192.168.1.1 to queue number 1. The detail
271 explanation of the ``generate_ipv4_flow()`` appears later in this document:
272
273 .. code-block:: c
274
275    flow = generate_ipv4_flow(port_id, selected_queue,
276                              SRC_IP, EMPTY_MASK,
277                              DEST_IP, FULL_MASK, &error);
278
279 We are setting the RX port to promiscuous mode:
280
281 .. code-block:: c
282
283    rte_eth_promiscuous_enable(port_id);
284
285 The last step is to start the port.
286
287 .. code-block:: c
288
289    ret = rte_eth_dev_start(port_id);
290    if (ret < 0)  {
291         rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err%d, port=%u\n",
292                         ret, port_id);
293    }
294
295
296 The main_loop function
297 ~~~~~~~~~~~~~~~~~~~~~~
298
299 As we saw above the ``main()`` function calls an application function to handle
300 the main loop. For the flow filtering application the main_loop function
301 looks like the following:
302
303 .. code-block:: c
304
305    static void
306    main_loop(void)
307    {
308            struct rte_mbuf *mbufs[32];
309            struct ether_hdr *eth_hdr;
310            uint16_t nb_rx;
311            uint16_t i;
312            uint16_t j;
313
314            while (!force_quit) {
315                    for (i = 0; i < nr_queues; i++) {
316                            nb_rx = rte_eth_rx_burst(port_id,
317                                                    i, mbufs, 32);
318                            if (nb_rx) {
319                                    for (j = 0; j < nb_rx; j++) {
320                                            struct rte_mbuf *m = mbufs[j];
321
322                                            eth_hdr = rte_pktmbuf_mtod(m,
323                                                         struct ether_hdr *);
324                                            print_ether_addr("src=",
325                                                         &eth_hdr->s_addr);
326                                            print_ether_addr(" - dst=",
327                                                         &eth_hdr->d_addr);
328                                            printf(" - queue=0x%x",
329                                                            (unsigned int)i);
330                                            printf("\n");
331                                            rte_pktmbuf_free(m);
332                                    }
333                            }
334                    }
335            }
336            /* closing and releasing resources */
337            rte_flow_flush(port_id, &error);
338            rte_eth_dev_stop(port_id);
339            rte_eth_dev_close(port_id);
340    }
341
342 The main work of the application is reading the packets from all
343 queues and printing for each packet the destination queue:
344
345 .. code-block:: c
346
347     while (!force_quit) {
348         for (i = 0; i < nr_queues; i++) {
349                    nb_rx = rte_eth_rx_burst(port_id, i, mbufs, 32);
350                 if (nb_rx) {
351                         for (j = 0; j < nb_rx; j++) {
352                              struct rte_mbuf *m = mbufs[j];
353                              eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
354                              print_ether_addr("src=", &eth_hdr->s_addr);
355                              print_ether_addr(" - dst=", &eth_hdr->d_addr);
356                              printf(" - queue=0x%x", (unsigned int)i);
357                              printf("\n");
358                              rte_pktmbuf_free(m);
359                         }
360                 }
361            }
362     }
363
364
365 The forwarding loop can be interrupted and the application closed using
366 ``Ctrl-C``. Which results in closing the port and the device using
367 ``rte_eth_dev_stop`` and ``rte_eth_dev_close``
368
369 The generate_ipv4_flow function
370 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
371
372 The generate_ipv4_rule function is responsible for creating the flow rule.
373 This function is located in the ``flow_blocks.c`` file.
374
375 .. code-block:: c
376
377    static struct rte_flow *
378    generate_ipv4_flow(uint8_t port_id, uint16_t rx_q,
379                    uint32_t src_ip, uint32_t src_mask,
380                    uint32_t dest_ip, uint32_t dest_mask,
381                    struct rte_flow_error *error)
382    {
383            struct rte_flow_attr attr;
384            struct rte_flow_item pattern[MAX_PATTERN_NUM];
385            struct rte_flow_action action[MAX_PATTERN_NUM];
386            struct rte_flow *flow = NULL;
387            struct rte_flow_action_queue queue = { .index = rx_q };
388            struct rte_flow_item_eth eth_spec;
389            struct rte_flow_item_eth eth_mask;
390            struct rte_flow_item_vlan vlan_spec;
391            struct rte_flow_item_vlan vlan_mask;
392            struct rte_flow_item_ipv4 ip_spec;
393            struct rte_flow_item_ipv4 ip_mask;
394
395            memset(pattern, 0, sizeof(pattern));
396            memset(action, 0, sizeof(action));
397
398            /*
399             * set the rule attribute.
400             * in this case only ingress packets will be checked.
401             */
402            memset(&attr, 0, sizeof(struct rte_flow_attr));
403            attr.ingress = 1;
404
405            /*
406             * create the action sequence.
407             * one action only,  move packet to queue
408             */
409
410            action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
411            action[0].conf = &queue;
412            action[1].type = RTE_FLOW_ACTION_TYPE_END;
413
414            /*
415             * set the first level of the pattern (eth).
416             * since in this example we just want to get the
417             * ipv4 we set this level to allow all.
418             */
419            memset(&eth_spec, 0, sizeof(struct rte_flow_item_eth));
420            memset(&eth_mask, 0, sizeof(struct rte_flow_item_eth));
421            eth_spec.type = 0;
422            eth_mask.type = 0;
423            pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
424            pattern[0].spec = &eth_spec;
425            pattern[0].mask = &eth_mask;
426
427            /*
428             * setting the second level of the pattern (vlan).
429             * since in this example we just want to get the
430             * ipv4 we also set this level to allow all.
431             */
432            memset(&vlan_spec, 0, sizeof(struct rte_flow_item_vlan));
433            memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
434            pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
435            pattern[1].spec = &vlan_spec;
436            pattern[1].mask = &vlan_mask;
437
438            /*
439             * setting the third level of the pattern (ip).
440             * in this example this is the level we care about
441             * so we set it according to the parameters.
442             */
443            memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4));
444            memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4));
445            ip_spec.hdr.dst_addr = htonl(dest_ip);
446            ip_mask.hdr.dst_addr = dest_mask;
447            ip_spec.hdr.src_addr = htonl(src_ip);
448            ip_mask.hdr.src_addr = src_mask;
449            pattern[2].type = RTE_FLOW_ITEM_TYPE_IPV4;
450            pattern[2].spec = &ip_spec;
451            pattern[2].mask = &ip_mask;
452
453            /* the final level must be always type end */
454            pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
455
456            int res = rte_flow_validate(port_id, &attr, pattern, action, error);
457            if(!res)
458                flow = rte_flow_create(port_id, &attr, pattern, action, error);
459
460            return flow;
461    }
462
463 The first part of the function is declaring the structures that will be used.
464
465 .. code-block:: c
466
467    struct rte_flow_attr attr;
468    struct rte_flow_item pattern[MAX_PATTERN_NUM];
469    struct rte_flow_action action[MAX_PATTERN_NUM];
470    struct rte_flow *flow;
471    struct rte_flow_error error;
472    struct rte_flow_action_queue queue = { .index = rx_q };
473    struct rte_flow_item_eth eth_spec;
474    struct rte_flow_item_eth eth_mask;
475    struct rte_flow_item_vlan vlan_spec;
476    struct rte_flow_item_vlan vlan_mask;
477    struct rte_flow_item_ipv4 ip_spec;
478    struct rte_flow_item_ipv4 ip_mask;
479
480 The following part create the flow attributes, in our case ingress.
481
482 .. code-block:: c
483
484    memset(&attr, 0, sizeof(struct rte_flow_attr));
485    attr.ingress = 1;
486
487 The third part defines the action to be taken when a packet matches
488 the rule. In this case send the packet to queue.
489
490 .. code-block:: c
491
492    action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
493    action[0].conf = &queue;
494    action[1].type = RTE_FLOW_ACTION_TYPE_END;
495
496 The forth part is responsible for creating the pattern and is build from
497 number of step. In each step we build one level of the pattern starting with
498 the lowest one.
499
500 Setting the first level of the pattern ETH:
501
502 .. code-block:: c
503
504    memset(&eth_spec, 0, sizeof(struct rte_flow_item_eth));
505    memset(&eth_mask, 0, sizeof(struct rte_flow_item_eth));
506    eth_spec.type = 0;
507    eth_mask.type = 0;
508    pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
509    pattern[0].spec = &eth_spec;
510    pattern[0].mask = &eth_mask;
511
512 Setting the second level of the pattern VLAN:
513
514 .. code-block:: c
515
516    memset(&vlan_spec, 0, sizeof(struct rte_flow_item_vlan));
517    memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
518    pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
519    pattern[1].spec = &vlan_spec;
520    pattern[1].mask = &vlan_mask;
521
522 Setting the third level ip:
523
524 .. code-block:: c
525
526    memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4));
527    memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4));
528    ip_spec.hdr.dst_addr = htonl(dest_ip);
529    ip_mask.hdr.dst_addr = dest_mask;
530    ip_spec.hdr.src_addr = htonl(src_ip);
531    ip_mask.hdr.src_addr = src_mask;
532    pattern[2].type = RTE_FLOW_ITEM_TYPE_IPV4;
533    pattern[2].spec = &ip_spec;
534    pattern[2].mask = &ip_mask;
535
536 Closing the pattern part.
537
538 .. code-block:: c
539
540    pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
541
542 The last part of the function is to validate the rule and create it.
543
544 .. code-block:: c
545
546    int res = rte_flow_validate(port_id, &attr, pattern, action, &error);
547    if (!res)
548         flow = rte_flow_create(port_id, &attr, pattern, action, &error);
549