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 = {
142 .offloads = DEV_RX_OFFLOAD_CRC_STRIP,
146 DEV_TX_OFFLOAD_VLAN_INSERT |
147 DEV_TX_OFFLOAD_IPV4_CKSUM |
148 DEV_TX_OFFLOAD_UDP_CKSUM |
149 DEV_TX_OFFLOAD_TCP_CKSUM |
150 DEV_TX_OFFLOAD_SCTP_CKSUM |
151 DEV_TX_OFFLOAD_TCP_TSO,
154 struct rte_eth_txconf txq_conf;
155 struct rte_eth_rxconf rxq_conf;
156 struct rte_eth_dev_info dev_info;
158 printf(":: initializing port: %d\n", port_id);
159 ret = rte_eth_dev_configure(port_id,
160 nr_queues, nr_queues, &port_conf);
162 rte_exit(EXIT_FAILURE,
163 ":: cannot configure device: err=%d, port=%u\n",
167 rte_eth_dev_info_get(port_id, &dev_info);
168 rxq_conf = dev_info.default_rxconf;
169 rxq_conf.offloads = port_conf.rxmode.offloads;
170 /* only set Rx queues: something we care only so far */
171 for (i = 0; i < nr_queues; i++) {
172 ret = rte_eth_rx_queue_setup(port_id, i, 512,
173 rte_eth_dev_socket_id(port_id),
177 rte_exit(EXIT_FAILURE,
178 ":: Rx queue setup failed: err=%d, port=%u\n",
183 txq_conf = dev_info.default_txconf;
184 txq_conf.offloads = port_conf.txmode.offloads;
186 for (i = 0; i < nr_queues; i++) {
187 ret = rte_eth_tx_queue_setup(port_id, i, 512,
188 rte_eth_dev_socket_id(port_id),
191 rte_exit(EXIT_FAILURE,
192 ":: Tx queue setup failed: err=%d, port=%u\n",
197 rte_eth_promiscuous_enable(port_id);
198 ret = rte_eth_dev_start(port_id);
200 rte_exit(EXIT_FAILURE,
201 "rte_eth_dev_start:err=%d, port=%u\n",
205 assert_link_status();
207 printf(":: initializing port: %d done\n", port_id);
210 The Ethernet port is configured with default settings using the
211 ``rte_eth_dev_configure()`` function and the ``port_conf_default`` struct:
215 struct rte_eth_conf port_conf = {
218 .offloads = DEV_RX_OFFLOAD_CRC_STRIP,
222 DEV_TX_OFFLOAD_VLAN_INSERT |
223 DEV_TX_OFFLOAD_IPV4_CKSUM |
224 DEV_TX_OFFLOAD_UDP_CKSUM |
225 DEV_TX_OFFLOAD_TCP_CKSUM |
226 DEV_TX_OFFLOAD_SCTP_CKSUM |
227 DEV_TX_OFFLOAD_TCP_TSO,
231 ret = rte_eth_dev_configure(port_id, nr_queues, nr_queues, &port_conf);
233 rte_exit(EXIT_FAILURE,
234 ":: cannot configure device: err=%d, port=%u\n",
237 rte_eth_dev_info_get(port_id, &dev_info);
238 rxq_conf = dev_info.default_rxconf;
239 rxq_conf.offloads = port_conf.rxmode.offloads;
241 For this example we are configuring number of rx and tx queues that are connected
246 for (i = 0; i < nr_queues; i++) {
247 ret = rte_eth_rx_queue_setup(port_id, i, 512,
248 rte_eth_dev_socket_id(port_id),
252 rte_exit(EXIT_FAILURE,
253 ":: Rx queue setup failed: err=%d, port=%u\n",
258 for (i = 0; i < nr_queues; i++) {
259 ret = rte_eth_tx_queue_setup(port_id, i, 512,
260 rte_eth_dev_socket_id(port_id),
263 rte_exit(EXIT_FAILURE,
264 ":: Tx queue setup failed: err=%d, port=%u\n",
269 In the next step we create and apply the flow rule. which is to send packets
270 with destination ip equals to 192.168.1.1 to queue number 1. The detail
271 explanation of the ``generate_ipv4_flow()`` appears later in this document:
275 flow = generate_ipv4_flow(port_id, selected_queue,
277 DEST_IP, FULL_MASK, &error);
279 We are setting the RX port to promiscuous mode:
283 rte_eth_promiscuous_enable(port_id);
285 The last step is to start the port.
289 ret = rte_eth_dev_start(port_id);
291 rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err%d, port=%u\n",
296 The main_loop function
297 ~~~~~~~~~~~~~~~~~~~~~~
299 As we saw above the ``main()`` function calls an application function to handle
300 the main loop. For the flow filtering application the main_loop function
301 looks like the following:
308 struct rte_mbuf *mbufs[32];
309 struct ether_hdr *eth_hdr;
314 while (!force_quit) {
315 for (i = 0; i < nr_queues; i++) {
316 nb_rx = rte_eth_rx_burst(port_id,
319 for (j = 0; j < nb_rx; j++) {
320 struct rte_mbuf *m = mbufs[j];
322 eth_hdr = rte_pktmbuf_mtod(m,
324 print_ether_addr("src=",
326 print_ether_addr(" - dst=",
328 printf(" - queue=0x%x",
336 /* closing and releasing resources */
337 rte_flow_flush(port_id, &error);
338 rte_eth_dev_stop(port_id);
339 rte_eth_dev_close(port_id);
342 The main work of the application is reading the packets from all
343 queues and printing for each packet the destination queue:
347 while (!force_quit) {
348 for (i = 0; i < nr_queues; i++) {
349 nb_rx = rte_eth_rx_burst(port_id, i, mbufs, 32);
351 for (j = 0; j < nb_rx; j++) {
352 struct rte_mbuf *m = mbufs[j];
353 eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
354 print_ether_addr("src=", ð_hdr->s_addr);
355 print_ether_addr(" - dst=", ð_hdr->d_addr);
356 printf(" - queue=0x%x", (unsigned int)i);
365 The forwarding loop can be interrupted and the application closed using
366 ``Ctrl-C``. Which results in closing the port and the device using
367 ``rte_eth_dev_stop`` and ``rte_eth_dev_close``
369 The generate_ipv4_flow function
370 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
372 The generate_ipv4_rule function is responsible for creating the flow rule.
373 This function is located in the ``flow_blocks.c`` file.
377 static struct rte_flow *
378 generate_ipv4_flow(uint8_t port_id, uint16_t rx_q,
379 uint32_t src_ip, uint32_t src_mask,
380 uint32_t dest_ip, uint32_t dest_mask,
381 struct rte_flow_error *error)
383 struct rte_flow_attr attr;
384 struct rte_flow_item pattern[MAX_PATTERN_NUM];
385 struct rte_flow_action action[MAX_PATTERN_NUM];
386 struct rte_flow *flow = NULL;
387 struct rte_flow_action_queue queue = { .index = rx_q };
388 struct rte_flow_item_eth eth_spec;
389 struct rte_flow_item_eth eth_mask;
390 struct rte_flow_item_vlan vlan_spec;
391 struct rte_flow_item_vlan vlan_mask;
392 struct rte_flow_item_ipv4 ip_spec;
393 struct rte_flow_item_ipv4 ip_mask;
395 memset(pattern, 0, sizeof(pattern));
396 memset(action, 0, sizeof(action));
399 * set the rule attribute.
400 * in this case only ingress packets will be checked.
402 memset(&attr, 0, sizeof(struct rte_flow_attr));
406 * create the action sequence.
407 * one action only, move packet to queue
410 action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
411 action[0].conf = &queue;
412 action[1].type = RTE_FLOW_ACTION_TYPE_END;
415 * set the first level of the pattern (eth).
416 * since in this example we just want to get the
417 * ipv4 we set this level to allow all.
419 memset(ð_spec, 0, sizeof(struct rte_flow_item_eth));
420 memset(ð_mask, 0, sizeof(struct rte_flow_item_eth));
423 pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
424 pattern[0].spec = ð_spec;
425 pattern[0].mask = ð_mask;
428 * setting the second level of the pattern (vlan).
429 * since in this example we just want to get the
430 * ipv4 we also set this level to allow all.
432 memset(&vlan_spec, 0, sizeof(struct rte_flow_item_vlan));
433 memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
434 pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
435 pattern[1].spec = &vlan_spec;
436 pattern[1].mask = &vlan_mask;
439 * setting the third level of the pattern (ip).
440 * in this example this is the level we care about
441 * so we set it according to the parameters.
443 memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4));
444 memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4));
445 ip_spec.hdr.dst_addr = htonl(dest_ip);
446 ip_mask.hdr.dst_addr = dest_mask;
447 ip_spec.hdr.src_addr = htonl(src_ip);
448 ip_mask.hdr.src_addr = src_mask;
449 pattern[2].type = RTE_FLOW_ITEM_TYPE_IPV4;
450 pattern[2].spec = &ip_spec;
451 pattern[2].mask = &ip_mask;
453 /* the final level must be always type end */
454 pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
456 int res = rte_flow_validate(port_id, &attr, pattern, action, error);
458 flow = rte_flow_create(port_id, &attr, pattern, action, error);
463 The first part of the function is declaring the structures that will be used.
467 struct rte_flow_attr attr;
468 struct rte_flow_item pattern[MAX_PATTERN_NUM];
469 struct rte_flow_action action[MAX_PATTERN_NUM];
470 struct rte_flow *flow;
471 struct rte_flow_error error;
472 struct rte_flow_action_queue queue = { .index = rx_q };
473 struct rte_flow_item_eth eth_spec;
474 struct rte_flow_item_eth eth_mask;
475 struct rte_flow_item_vlan vlan_spec;
476 struct rte_flow_item_vlan vlan_mask;
477 struct rte_flow_item_ipv4 ip_spec;
478 struct rte_flow_item_ipv4 ip_mask;
480 The following part create the flow attributes, in our case ingress.
484 memset(&attr, 0, sizeof(struct rte_flow_attr));
487 The third part defines the action to be taken when a packet matches
488 the rule. In this case send the packet to queue.
492 action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
493 action[0].conf = &queue;
494 action[1].type = RTE_FLOW_ACTION_TYPE_END;
496 The forth part is responsible for creating the pattern and is build from
497 number of step. In each step we build one level of the pattern starting with
500 Setting the first level of the pattern ETH:
504 memset(ð_spec, 0, sizeof(struct rte_flow_item_eth));
505 memset(ð_mask, 0, sizeof(struct rte_flow_item_eth));
508 pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
509 pattern[0].spec = ð_spec;
510 pattern[0].mask = ð_mask;
512 Setting the second level of the pattern VLAN:
516 memset(&vlan_spec, 0, sizeof(struct rte_flow_item_vlan));
517 memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
518 pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
519 pattern[1].spec = &vlan_spec;
520 pattern[1].mask = &vlan_mask;
522 Setting the third level ip:
526 memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4));
527 memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4));
528 ip_spec.hdr.dst_addr = htonl(dest_ip);
529 ip_mask.hdr.dst_addr = dest_mask;
530 ip_spec.hdr.src_addr = htonl(src_ip);
531 ip_mask.hdr.src_addr = src_mask;
532 pattern[2].type = RTE_FLOW_ITEM_TYPE_IPV4;
533 pattern[2].spec = &ip_spec;
534 pattern[2].mask = &ip_mask;
536 Closing the pattern part.
540 pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
542 The last part of the function is to validate the rule and create it.
546 int res = rte_flow_validate(port_id, &attr, pattern, action, &error);
548 flow = rte_flow_create(port_id, &attr, pattern, action, &error);