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