net: add rte prefix to ether structures
[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-linux-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 ``linux`` 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 built from 2 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 rte_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 rte_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 rte_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_flow 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_ACTION_NUM];
384            struct rte_flow *flow = NULL;
385            struct rte_flow_action_queue queue = { .index = rx_q };
386            struct rte_flow_item_ipv4 ip_spec;
387            struct rte_flow_item_ipv4 ip_mask;
388
389            memset(pattern, 0, sizeof(pattern));
390            memset(action, 0, sizeof(action));
391
392            /*
393             * set the rule attribute.
394             * in this case only ingress packets will be checked.
395             */
396            memset(&attr, 0, sizeof(struct rte_flow_attr));
397            attr.ingress = 1;
398
399            /*
400             * create the action sequence.
401             * one action only,  move packet to queue
402             */
403            action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
404            action[0].conf = &queue;
405            action[1].type = RTE_FLOW_ACTION_TYPE_END;
406
407            /*
408             * set the first level of the pattern (ETH).
409             * since in this example we just want to get the
410             * ipv4 we set this level to allow all.
411             */
412            pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
413
414            /*
415             * setting the second level of the pattern (IP).
416             * in this example this is the level we care about
417             * so we set it according to the parameters.
418             */
419            memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4));
420            memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4));
421            ip_spec.hdr.dst_addr = htonl(dest_ip);
422            ip_mask.hdr.dst_addr = dest_mask;
423            ip_spec.hdr.src_addr = htonl(src_ip);
424            ip_mask.hdr.src_addr = src_mask;
425            pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
426            pattern[1].spec = &ip_spec;
427            pattern[1].mask = &ip_mask;
428
429            /* the final level must be always type end */
430            pattern[2].type = RTE_FLOW_ITEM_TYPE_END;
431
432            int res = rte_flow_validate(port_id, &attr, pattern, action, error);
433            if(!res)
434                flow = rte_flow_create(port_id, &attr, pattern, action, error);
435
436            return flow;
437    }
438
439 The first part of the function is declaring the structures that will be used.
440
441 .. code-block:: c
442
443    struct rte_flow_attr attr;
444    struct rte_flow_item pattern[MAX_PATTERN_NUM];
445    struct rte_flow_action action[MAX_ACTION_NUM];
446    struct rte_flow *flow;
447    struct rte_flow_error error;
448    struct rte_flow_action_queue queue = { .index = rx_q };
449    struct rte_flow_item_ipv4 ip_spec;
450    struct rte_flow_item_ipv4 ip_mask;
451
452 The following part create the flow attributes, in our case ingress.
453
454 .. code-block:: c
455
456    memset(&attr, 0, sizeof(struct rte_flow_attr));
457    attr.ingress = 1;
458
459 The third part defines the action to be taken when a packet matches
460 the rule. In this case send the packet to queue.
461
462 .. code-block:: c
463
464    action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
465    action[0].conf = &queue;
466    action[1].type = RTE_FLOW_ACTION_TYPE_END;
467
468 The fourth part is responsible for creating the pattern and is built from
469 number of steps. In each step we build one level of the pattern starting with
470 the lowest one.
471
472 Setting the first level of the pattern ETH:
473
474 .. code-block:: c
475
476    pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
477
478 Setting the second level of the pattern IP:
479
480 .. code-block:: c
481
482    memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4));
483    memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4));
484    ip_spec.hdr.dst_addr = htonl(dest_ip);
485    ip_mask.hdr.dst_addr = dest_mask;
486    ip_spec.hdr.src_addr = htonl(src_ip);
487    ip_mask.hdr.src_addr = src_mask;
488    pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
489    pattern[1].spec = &ip_spec;
490    pattern[1].mask = &ip_mask;
491
492 Closing the pattern part.
493
494 .. code-block:: c
495
496    pattern[2].type = RTE_FLOW_ITEM_TYPE_END;
497
498 The last part of the function is to validate the rule and create it.
499
500 .. code-block:: c
501
502    int res = rte_flow_validate(port_id, &attr, pattern, action, &error);
503    if (!res)
504         flow = rte_flow_create(port_id, &attr, pattern, action, &error);
505