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-linuxapp-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 ``linuxapp`` 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 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.
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 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,
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 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_PATTERN_NUM];
384 struct rte_flow *flow = NULL;
385 struct rte_flow_action_queue queue = { .index = rx_q };
386 struct rte_flow_item_eth eth_spec;
387 struct rte_flow_item_eth eth_mask;
388 struct rte_flow_item_vlan vlan_spec;
389 struct rte_flow_item_vlan vlan_mask;
390 struct rte_flow_item_ipv4 ip_spec;
391 struct rte_flow_item_ipv4 ip_mask;
393 memset(pattern, 0, sizeof(pattern));
394 memset(action, 0, sizeof(action));
397 * set the rule attribute.
398 * in this case only ingress packets will be checked.
400 memset(&attr, 0, sizeof(struct rte_flow_attr));
404 * create the action sequence.
405 * one action only, move packet to queue
408 action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
409 action[0].conf = &queue;
410 action[1].type = RTE_FLOW_ACTION_TYPE_END;
413 * set the first level of the pattern (eth).
414 * since in this example we just want to get the
415 * ipv4 we set this level to allow all.
417 memset(ð_spec, 0, sizeof(struct rte_flow_item_eth));
418 memset(ð_mask, 0, sizeof(struct rte_flow_item_eth));
421 pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
422 pattern[0].spec = ð_spec;
423 pattern[0].mask = ð_mask;
426 * setting the second level of the pattern (vlan).
427 * since in this example we just want to get the
428 * ipv4 we also set this level to allow all.
430 memset(&vlan_spec, 0, sizeof(struct rte_flow_item_vlan));
431 memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
432 pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
433 pattern[1].spec = &vlan_spec;
434 pattern[1].mask = &vlan_mask;
437 * setting the third level of the pattern (ip).
438 * in this example this is the level we care about
439 * so we set it according to the parameters.
441 memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4));
442 memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4));
443 ip_spec.hdr.dst_addr = htonl(dest_ip);
444 ip_mask.hdr.dst_addr = dest_mask;
445 ip_spec.hdr.src_addr = htonl(src_ip);
446 ip_mask.hdr.src_addr = src_mask;
447 pattern[2].type = RTE_FLOW_ITEM_TYPE_IPV4;
448 pattern[2].spec = &ip_spec;
449 pattern[2].mask = &ip_mask;
451 /* the final level must be always type end */
452 pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
454 int res = rte_flow_validate(port_id, &attr, pattern, action, error);
456 flow = rte_flow_create(port_id, &attr, pattern, action, error);
461 The first part of the function is declaring the structures that will be used.
465 struct rte_flow_attr attr;
466 struct rte_flow_item pattern[MAX_PATTERN_NUM];
467 struct rte_flow_action action[MAX_PATTERN_NUM];
468 struct rte_flow *flow;
469 struct rte_flow_error error;
470 struct rte_flow_action_queue queue = { .index = rx_q };
471 struct rte_flow_item_eth eth_spec;
472 struct rte_flow_item_eth eth_mask;
473 struct rte_flow_item_vlan vlan_spec;
474 struct rte_flow_item_vlan vlan_mask;
475 struct rte_flow_item_ipv4 ip_spec;
476 struct rte_flow_item_ipv4 ip_mask;
478 The following part create the flow attributes, in our case ingress.
482 memset(&attr, 0, sizeof(struct rte_flow_attr));
485 The third part defines the action to be taken when a packet matches
486 the rule. In this case send the packet to queue.
490 action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
491 action[0].conf = &queue;
492 action[1].type = RTE_FLOW_ACTION_TYPE_END;
494 The forth part is responsible for creating the pattern and is build from
495 number of step. In each step we build one level of the pattern starting with
498 Setting the first level of the pattern ETH:
502 memset(ð_spec, 0, sizeof(struct rte_flow_item_eth));
503 memset(ð_mask, 0, sizeof(struct rte_flow_item_eth));
506 pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
507 pattern[0].spec = ð_spec;
508 pattern[0].mask = ð_mask;
510 Setting the second level of the pattern VLAN:
514 memset(&vlan_spec, 0, sizeof(struct rte_flow_item_vlan));
515 memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
516 pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
517 pattern[1].spec = &vlan_spec;
518 pattern[1].mask = &vlan_mask;
520 Setting the third level ip:
524 memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4));
525 memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4));
526 ip_spec.hdr.dst_addr = htonl(dest_ip);
527 ip_mask.hdr.dst_addr = dest_mask;
528 ip_spec.hdr.src_addr = htonl(src_ip);
529 ip_mask.hdr.src_addr = src_mask;
530 pattern[2].type = RTE_FLOW_ITEM_TYPE_IPV4;
531 pattern[2].spec = &ip_spec;
532 pattern[2].mask = &ip_mask;
534 Closing the pattern part.
538 pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
540 The last part of the function is to validate the rule and create it.
544 int res = rte_flow_validate(port_id, &attr, pattern, action, &error);
546 flow = rte_flow_create(port_id, &attr, pattern, action, &error);