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 .ignore_offload_bitfield = 1,
143 .offloads = DEV_RX_OFFLOAD_CRC_STRIP,
147 DEV_TX_OFFLOAD_VLAN_INSERT |
148 DEV_TX_OFFLOAD_IPV4_CKSUM |
149 DEV_TX_OFFLOAD_UDP_CKSUM |
150 DEV_TX_OFFLOAD_TCP_CKSUM |
151 DEV_TX_OFFLOAD_SCTP_CKSUM |
152 DEV_TX_OFFLOAD_TCP_TSO,
155 struct rte_eth_txconf txq_conf;
156 struct rte_eth_rxconf rxq_conf;
157 struct rte_eth_dev_info dev_info;
159 printf(":: initializing port: %d\n", port_id);
160 ret = rte_eth_dev_configure(port_id,
161 nr_queues, nr_queues, &port_conf);
163 rte_exit(EXIT_FAILURE,
164 ":: cannot configure device: err=%d, port=%u\n",
168 rte_eth_dev_info_get(port_id, &dev_info);
169 rxq_conf = dev_info.default_rxconf;
170 rxq_conf.offloads = port_conf.rxmode.offloads;
171 /* only set Rx queues: something we care only so far */
172 for (i = 0; i < nr_queues; i++) {
173 ret = rte_eth_rx_queue_setup(port_id, i, 512,
174 rte_eth_dev_socket_id(port_id),
178 rte_exit(EXIT_FAILURE,
179 ":: Rx queue setup failed: err=%d, port=%u\n",
184 txq_conf = dev_info.default_txconf;
185 txq_conf.offloads = port_conf.txmode.offloads;
187 for (i = 0; i < nr_queues; i++) {
188 ret = rte_eth_tx_queue_setup(port_id, i, 512,
189 rte_eth_dev_socket_id(port_id),
192 rte_exit(EXIT_FAILURE,
193 ":: Tx queue setup failed: err=%d, port=%u\n",
198 rte_eth_promiscuous_enable(port_id);
199 ret = rte_eth_dev_start(port_id);
201 rte_exit(EXIT_FAILURE,
202 "rte_eth_dev_start:err=%d, port=%u\n",
206 assert_link_status();
208 printf(":: initializing port: %d done\n", port_id);
211 The Ethernet port is configured with default settings using the
212 ``rte_eth_dev_configure()`` function and the ``port_conf_default`` struct:
216 struct rte_eth_conf port_conf = {
219 .ignore_offload_bitfield = 1,
220 .offloads = DEV_RX_OFFLOAD_CRC_STRIP,
224 DEV_TX_OFFLOAD_VLAN_INSERT |
225 DEV_TX_OFFLOAD_IPV4_CKSUM |
226 DEV_TX_OFFLOAD_UDP_CKSUM |
227 DEV_TX_OFFLOAD_TCP_CKSUM |
228 DEV_TX_OFFLOAD_SCTP_CKSUM |
229 DEV_TX_OFFLOAD_TCP_TSO,
233 ret = rte_eth_dev_configure(port_id, nr_queues, nr_queues, &port_conf);
235 rte_exit(EXIT_FAILURE,
236 ":: cannot configure device: err=%d, port=%u\n",
239 rte_eth_dev_info_get(port_id, &dev_info);
240 rxq_conf = dev_info.default_rxconf;
241 rxq_conf.offloads = port_conf.rxmode.offloads;
243 For this example we are configuring number of rx and tx queues that are connected
248 for (i = 0; i < nr_queues; i++) {
249 ret = rte_eth_rx_queue_setup(port_id, i, 512,
250 rte_eth_dev_socket_id(port_id),
254 rte_exit(EXIT_FAILURE,
255 ":: Rx queue setup failed: err=%d, port=%u\n",
260 for (i = 0; i < nr_queues; i++) {
261 ret = rte_eth_tx_queue_setup(port_id, i, 512,
262 rte_eth_dev_socket_id(port_id),
265 rte_exit(EXIT_FAILURE,
266 ":: Tx queue setup failed: err=%d, port=%u\n",
271 In the next step we create and apply the flow rule. which is to send packets
272 with destination ip equals to 192.168.1.1 to queue number 1. The detail
273 explanation of the ``generate_ipv4_flow()`` appears later in this document:
277 flow = generate_ipv4_flow(port_id, selected_queue,
279 DEST_IP, FULL_MASK, &error);
281 We are setting the RX port to promiscuous mode:
285 rte_eth_promiscuous_enable(port_id);
287 The last step is to start the port.
291 ret = rte_eth_dev_start(port_id);
293 rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err%d, port=%u\n",
298 The main_loop function
299 ~~~~~~~~~~~~~~~~~~~~~~
301 As we saw above the ``main()`` function calls an application function to handle
302 the main loop. For the flow filtering application the main_loop function
303 looks like the following:
310 struct rte_mbuf *mbufs[32];
311 struct ether_hdr *eth_hdr;
316 while (!force_quit) {
317 for (i = 0; i < nr_queues; i++) {
318 nb_rx = rte_eth_rx_burst(port_id,
321 for (j = 0; j < nb_rx; j++) {
322 struct rte_mbuf *m = mbufs[j];
324 eth_hdr = rte_pktmbuf_mtod(m,
326 print_ether_addr("src=",
328 print_ether_addr(" - dst=",
330 printf(" - queue=0x%x",
338 /* closing and releasing resources */
339 rte_flow_flush(port_id, &error);
340 rte_eth_dev_stop(port_id);
341 rte_eth_dev_close(port_id);
344 The main work of the application is reading the packets from all
345 queues and printing for each packet the destination queue:
349 while (!force_quit) {
350 for (i = 0; i < nr_queues; i++) {
351 nb_rx = rte_eth_rx_burst(port_id, i, mbufs, 32);
353 for (j = 0; j < nb_rx; j++) {
354 struct rte_mbuf *m = mbufs[j];
355 eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
356 print_ether_addr("src=", ð_hdr->s_addr);
357 print_ether_addr(" - dst=", ð_hdr->d_addr);
358 printf(" - queue=0x%x", (unsigned int)i);
367 The forwarding loop can be interrupted and the application closed using
368 ``Ctrl-C``. Which results in closing the port and the device using
369 ``rte_eth_dev_stop`` and ``rte_eth_dev_close``
371 The generate_ipv4_flow function
372 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
374 The generate_ipv4_rule function is responsible for creating the flow rule.
375 This function is located in the ``flow_blocks.c`` file.
379 static struct rte_flow *
380 generate_ipv4_flow(uint8_t port_id, uint16_t rx_q,
381 uint32_t src_ip, uint32_t src_mask,
382 uint32_t dest_ip, uint32_t dest_mask,
383 struct rte_flow_error *error)
385 struct rte_flow_attr attr;
386 struct rte_flow_item pattern[MAX_PATTERN_NUM];
387 struct rte_flow_action action[MAX_PATTERN_NUM];
388 struct rte_flow *flow = NULL;
389 struct rte_flow_action_queue queue = { .index = rx_q };
390 struct rte_flow_item_eth eth_spec;
391 struct rte_flow_item_eth eth_mask;
392 struct rte_flow_item_vlan vlan_spec;
393 struct rte_flow_item_vlan vlan_mask;
394 struct rte_flow_item_ipv4 ip_spec;
395 struct rte_flow_item_ipv4 ip_mask;
397 memset(pattern, 0, sizeof(pattern));
398 memset(action, 0, sizeof(action));
401 * set the rule attribute.
402 * in this case only ingress packets will be checked.
404 memset(&attr, 0, sizeof(struct rte_flow_attr));
408 * create the action sequence.
409 * one action only, move packet to queue
412 action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
413 action[0].conf = &queue;
414 action[1].type = RTE_FLOW_ACTION_TYPE_END;
417 * set the first level of the pattern (eth).
418 * since in this example we just want to get the
419 * ipv4 we set this level to allow all.
421 memset(ð_spec, 0, sizeof(struct rte_flow_item_eth));
422 memset(ð_mask, 0, sizeof(struct rte_flow_item_eth));
425 pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
426 pattern[0].spec = ð_spec;
427 pattern[0].mask = ð_mask;
430 * setting the second level of the pattern (vlan).
431 * since in this example we just want to get the
432 * ipv4 we also set this level to allow all.
434 memset(&vlan_spec, 0, sizeof(struct rte_flow_item_vlan));
435 memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
436 pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
437 pattern[1].spec = &vlan_spec;
438 pattern[1].mask = &vlan_mask;
441 * setting the third level of the pattern (ip).
442 * in this example this is the level we care about
443 * so we set it according to the parameters.
445 memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4));
446 memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4));
447 ip_spec.hdr.dst_addr = htonl(dest_ip);
448 ip_mask.hdr.dst_addr = dest_mask;
449 ip_spec.hdr.src_addr = htonl(src_ip);
450 ip_mask.hdr.src_addr = src_mask;
451 pattern[2].type = RTE_FLOW_ITEM_TYPE_IPV4;
452 pattern[2].spec = &ip_spec;
453 pattern[2].mask = &ip_mask;
455 /* the final level must be always type end */
456 pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
458 int res = rte_flow_validate(port_id, &attr, pattern, action, error);
460 flow = rte_flow_create(port_id, &attr, pattern, action, error);
465 The first part of the function is declaring the structures that will be used.
469 struct rte_flow_attr attr;
470 struct rte_flow_item pattern[MAX_PATTERN_NUM];
471 struct rte_flow_action action[MAX_PATTERN_NUM];
472 struct rte_flow *flow;
473 struct rte_flow_error error;
474 struct rte_flow_action_queue queue = { .index = rx_q };
475 struct rte_flow_item_eth eth_spec;
476 struct rte_flow_item_eth eth_mask;
477 struct rte_flow_item_vlan vlan_spec;
478 struct rte_flow_item_vlan vlan_mask;
479 struct rte_flow_item_ipv4 ip_spec;
480 struct rte_flow_item_ipv4 ip_mask;
482 The following part create the flow attributes, in our case ingress.
486 memset(&attr, 0, sizeof(struct rte_flow_attr));
489 The third part defines the action to be taken when a packet matches
490 the rule. In this case send the packet to queue.
494 action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
495 action[0].conf = &queue;
496 action[1].type = RTE_FLOW_ACTION_TYPE_END;
498 The forth part is responsible for creating the pattern and is build from
499 number of step. In each step we build one level of the pattern starting with
502 Setting the first level of the pattern ETH:
506 memset(ð_spec, 0, sizeof(struct rte_flow_item_eth));
507 memset(ð_mask, 0, sizeof(struct rte_flow_item_eth));
510 pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
511 pattern[0].spec = ð_spec;
512 pattern[0].mask = ð_mask;
514 Setting the second level of the pattern VLAN:
518 memset(&vlan_spec, 0, sizeof(struct rte_flow_item_vlan));
519 memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
520 pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
521 pattern[1].spec = &vlan_spec;
522 pattern[1].mask = &vlan_mask;
524 Setting the third level ip:
528 memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4));
529 memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4));
530 ip_spec.hdr.dst_addr = htonl(dest_ip);
531 ip_mask.hdr.dst_addr = dest_mask;
532 ip_spec.hdr.src_addr = htonl(src_ip);
533 ip_mask.hdr.src_addr = src_mask;
534 pattern[2].type = RTE_FLOW_ITEM_TYPE_IPV4;
535 pattern[2].spec = &ip_spec;
536 pattern[2].mask = &ip_mask;
538 Closing the pattern part.
542 pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
544 The last part of the function is to validate the rule and create it.
548 int res = rte_flow_validate(port_id, &attr, pattern, action, &error);
550 flow = rte_flow_create(port_id, &attr, pattern, action, &error);