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