1 .. SPDX-License-Identifier: BSD-3-Clause
2 Copyright 2017 Mellanox Technologies, Ltd
4 Basic RTE Flow Filtering Sample Application
5 ===========================================
7 The Basic RTE flow filtering sample application is a simple example of a
8 creating a RTE flow rule.
10 It is intended as a demonstration of the basic components RTE flow rules.
13 Compiling the Application
14 -------------------------
16 To compile the application export the path to the DPDK source tree and go to
17 the example directory:
19 .. code-block:: console
21 export RTE_SDK=/path/to/rte_sdk
23 cd ${RTE_SDK}/examples/flow_filtering
25 Set the target, for example:
27 .. code-block:: console
29 export RTE_TARGET=x86_64-native-linux-gcc
31 See the *DPDK Getting Started* Guide for possible ``RTE_TARGET`` values.
33 Build the application as follows:
35 .. code-block:: console
40 Running the Application
41 -----------------------
43 To run the example in a ``linux`` environment:
45 .. code-block:: console
47 ./build/flow -l 1 -n 1
49 Refer to *DPDK Getting Started Guide* for general information on running
50 applications and the Environment Abstraction Layer (EAL) options.
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.
60 The following sections provide an explanation of the main components of the
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*.
70 The ``main()`` function located in ``main.c`` file performs the initialization
71 and runs the main loop function.
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:
79 int ret = rte_eal_init(argc, argv);
81 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
84 The ``main()`` also allocates a mempool to hold the mbufs (Message Buffers)
85 used by the application:
89 mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", 4096, 128, 0,
90 RTE_MBUF_DEFAULT_BUF_SIZE,
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*.
96 The ``main()`` function also initializes all the ports using the user defined
97 ``init_port()`` function which is explained in the next section:
103 Once the initialization is complete, we set the flow rule using the
108 /* create flow for send packet with */
109 flow = generate_ipv4_flow(port_id, selected_queue,
111 DEST_IP, FULL_MASK, &error);
113 printf("Flow can't be created %d message: %s\n",
115 error.message ? error.message : "(no stated reason)");
116 rte_exit(EXIT_FAILURE, "error in creating flow");
119 In the last part the application is ready to launch the
120 ``main_loop()`` function. Which is explained below.
127 The Port Initialization Function
128 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
130 The main functional part of the port initialization used in the flow filtering
131 application is shown below:
139 struct rte_eth_conf port_conf = {
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,
153 struct rte_eth_txconf txq_conf;
154 struct rte_eth_rxconf rxq_conf;
155 struct rte_eth_dev_info dev_info;
157 printf(":: initializing port: %d\n", port_id);
158 ret = rte_eth_dev_configure(port_id,
159 nr_queues, nr_queues, &port_conf);
161 rte_exit(EXIT_FAILURE,
162 ":: cannot configure device: err=%d, port=%u\n",
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),
176 rte_exit(EXIT_FAILURE,
177 ":: Rx queue setup failed: err=%d, port=%u\n",
182 txq_conf = dev_info.default_txconf;
183 txq_conf.offloads = port_conf.txmode.offloads;
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),
190 rte_exit(EXIT_FAILURE,
191 ":: Tx queue setup failed: err=%d, port=%u\n",
196 rte_eth_promiscuous_enable(port_id);
197 ret = rte_eth_dev_start(port_id);
199 rte_exit(EXIT_FAILURE,
200 "rte_eth_dev_start:err=%d, port=%u\n",
204 assert_link_status();
206 printf(":: initializing port: %d done\n", port_id);
209 The Ethernet port is configured with default settings using the
210 ``rte_eth_dev_configure()`` function and the ``port_conf_default`` struct:
214 struct rte_eth_conf port_conf = {
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,
229 ret = rte_eth_dev_configure(port_id, nr_queues, nr_queues, &port_conf);
231 rte_exit(EXIT_FAILURE,
232 ":: cannot configure device: err=%d, port=%u\n",
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;
239 For this example we are configuring number of rx and tx queues that are connected
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),
250 rte_exit(EXIT_FAILURE,
251 ":: Rx queue setup failed: err=%d, port=%u\n",
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),
261 rte_exit(EXIT_FAILURE,
262 ":: Tx queue setup failed: err=%d, port=%u\n",
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:
273 flow = generate_ipv4_flow(port_id, selected_queue,
275 DEST_IP, FULL_MASK, &error);
277 We are setting the RX port to promiscuous mode:
281 rte_eth_promiscuous_enable(port_id);
283 The last step is to start the port.
287 ret = rte_eth_dev_start(port_id);
289 rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err%d, port=%u\n",
294 The main_loop function
295 ~~~~~~~~~~~~~~~~~~~~~~
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:
306 struct rte_mbuf *mbufs[32];
307 struct rte_ether_hdr *eth_hdr;
312 while (!force_quit) {
313 for (i = 0; i < nr_queues; i++) {
314 nb_rx = rte_eth_rx_burst(port_id,
317 for (j = 0; j < nb_rx; j++) {
318 struct rte_mbuf *m = mbufs[j];
320 eth_hdr = rte_pktmbuf_mtod(m,
321 struct rte_ether_hdr *);
322 print_ether_addr("src=",
324 print_ether_addr(" - dst=",
326 printf(" - queue=0x%x",
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);
340 The main work of the application is reading the packets from all
341 queues and printing for each packet the destination queue:
345 while (!force_quit) {
346 for (i = 0; i < nr_queues; i++) {
347 nb_rx = rte_eth_rx_burst(port_id, i, mbufs, 32);
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=", ð_hdr->s_addr);
353 print_ether_addr(" - dst=", ð_hdr->d_addr);
354 printf(" - queue=0x%x", (unsigned int)i);
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``
367 The generate_ipv4_flow function
368 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
370 The generate_ipv4_flow function is responsible for creating the flow rule.
371 This function is located in the ``flow_blocks.c`` file.
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)
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;
389 memset(pattern, 0, sizeof(pattern));
390 memset(action, 0, sizeof(action));
393 * set the rule attribute.
394 * in this case only ingress packets will be checked.
396 memset(&attr, 0, sizeof(struct rte_flow_attr));
400 * create the action sequence.
401 * one action only, move packet to queue
403 action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
404 action[0].conf = &queue;
405 action[1].type = RTE_FLOW_ACTION_TYPE_END;
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.
412 pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
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.
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;
429 /* the final level must be always type end */
430 pattern[2].type = RTE_FLOW_ITEM_TYPE_END;
432 int res = rte_flow_validate(port_id, &attr, pattern, action, error);
434 flow = rte_flow_create(port_id, &attr, pattern, action, error);
439 The first part of the function is declaring the structures that will be used.
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;
452 The following part create the flow attributes, in our case ingress.
456 memset(&attr, 0, sizeof(struct rte_flow_attr));
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.
464 action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
465 action[0].conf = &queue;
466 action[1].type = RTE_FLOW_ACTION_TYPE_END;
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
472 Setting the first level of the pattern ETH:
476 pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
478 Setting the second level of the pattern IP:
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;
492 Closing the pattern part.
496 pattern[2].type = RTE_FLOW_ITEM_TYPE_END;
498 The last part of the function is to validate the rule and create it.
502 int res = rte_flow_validate(port_id, &attr, pattern, action, &error);
504 flow = rte_flow_create(port_id, &attr, pattern, action, &error);