2 Copyright(c) 2017 Mellanox Corporation. All rights reserved.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in
13 the documentation and/or other materials provided with the
15 * Neither the name of Mellanox Corporation nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 Basic RTE Flow Filtering Sample Application
33 ===========================================
35 The Basic RTE flow filtering sample application is a simple example of a
36 creating a RTE flow rule.
38 It is intended as a demonstration of the basic components RTE flow rules.
41 Compiling the Application
42 -------------------------
44 To compile the application export the path to the DPDK source tree and go to
45 the example directory:
47 .. code-block:: console
49 export RTE_SDK=/path/to/rte_sdk
51 cd ${RTE_SDK}/examples/flow_filtering
53 Set the target, for example:
55 .. code-block:: console
57 export RTE_TARGET=x86_64-native-linuxapp-gcc
59 See the *DPDK Getting Started* Guide for possible ``RTE_TARGET`` values.
61 Build the application as follows:
63 .. code-block:: console
68 Running the Application
69 -----------------------
71 To run the example in a ``linuxapp`` environment:
73 .. code-block:: console
75 ./build/flow -l 1 -n 1
77 Refer to *DPDK Getting Started Guide* for general information on running
78 applications and the Environment Abstraction Layer (EAL) options.
84 The example is build from 2 main files,
85 ``main.c`` which holds the example logic and ``flow_blocks.c`` that holds the
86 implementation for building the flow rule.
88 The following sections provide an explanation of the main components of the
91 All DPDK library functions used in the sample code are prefixed with ``rte_``
92 and are explained in detail in the *DPDK API Documentation*.
98 The ``main()`` function located in ``main.c`` file performs the initialization
99 and runs the main loop function.
101 The first task is to initialize the Environment Abstraction Layer (EAL). The
102 ``argc`` and ``argv`` arguments are provided to the ``rte_eal_init()``
103 function. The value returned is the number of parsed arguments:
107 int ret = rte_eal_init(argc, argv);
109 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
112 The ``main()`` also allocates a mempool to hold the mbufs (Message Buffers)
113 used by the application:
117 mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", 4096, 128, 0,
118 RTE_MBUF_DEFAULT_BUF_SIZE,
121 Mbufs are the packet buffer structure used by DPDK. They are explained in
122 detail in the "Mbuf Library" section of the *DPDK Programmer's Guide*.
124 The ``main()`` function also initializes all the ports using the user defined
125 ``init_port()`` function which is explained in the next section:
131 Once the initialization is complete, we set the flow rule using the
136 /* create flow for send packet with */
137 flow = generate_ipv4_flow(port_id, selected_queue,
139 DEST_IP, FULL_MASK, &error);
141 printf("Flow can't be created %d message: %s\n",
143 error.message ? error.message : "(no stated reason)");
144 rte_exit(EXIT_FAILURE, "error in creating flow");
147 In the last part the application is ready to launch the
148 ``main_loop()`` function. Which is explained below.
155 The Port Initialization Function
156 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
158 The main functional part of the port initialization used in the flow filtering
159 application is shown below:
167 struct rte_eth_conf port_conf = {
170 .ignore_offload_bitfield = 1,
171 .offloads = DEV_RX_OFFLOAD_CRC_STRIP,
175 DEV_TX_OFFLOAD_VLAN_INSERT |
176 DEV_TX_OFFLOAD_IPV4_CKSUM |
177 DEV_TX_OFFLOAD_UDP_CKSUM |
178 DEV_TX_OFFLOAD_TCP_CKSUM |
179 DEV_TX_OFFLOAD_SCTP_CKSUM |
180 DEV_TX_OFFLOAD_TCP_TSO,
183 struct rte_eth_txconf txq_conf;
184 struct rte_eth_rxconf rxq_conf;
185 struct rte_eth_dev_info dev_info;
187 printf(":: initializing port: %d\n", port_id);
188 ret = rte_eth_dev_configure(port_id,
189 nr_queues, nr_queues, &port_conf);
191 rte_exit(EXIT_FAILURE,
192 ":: cannot configure device: err=%d, port=%u\n",
196 rte_eth_dev_info_get(port_id, &dev_info);
197 rxq_conf = dev_info.default_rxconf;
198 rxq_conf.offloads = port_conf.rxmode.offloads;
199 /* only set Rx queues: something we care only so far */
200 for (i = 0; i < nr_queues; i++) {
201 ret = rte_eth_rx_queue_setup(port_id, i, 512,
202 rte_eth_dev_socket_id(port_id),
206 rte_exit(EXIT_FAILURE,
207 ":: Rx queue setup failed: err=%d, port=%u\n",
212 txq_conf = dev_info.default_txconf;
213 txq_conf.offloads = port_conf.txmode.offloads;
215 for (i = 0; i < nr_queues; i++) {
216 ret = rte_eth_tx_queue_setup(port_id, i, 512,
217 rte_eth_dev_socket_id(port_id),
220 rte_exit(EXIT_FAILURE,
221 ":: Tx queue setup failed: err=%d, port=%u\n",
226 rte_eth_promiscuous_enable(port_id);
227 ret = rte_eth_dev_start(port_id);
229 rte_exit(EXIT_FAILURE,
230 "rte_eth_dev_start:err=%d, port=%u\n",
234 assert_link_status();
236 printf(":: initializing port: %d done\n", port_id);
239 The Ethernet port is configured with default settings using the
240 ``rte_eth_dev_configure()`` function and the ``port_conf_default`` struct:
244 struct rte_eth_conf port_conf = {
247 .ignore_offload_bitfield = 1,
248 .offloads = DEV_RX_OFFLOAD_CRC_STRIP,
252 DEV_TX_OFFLOAD_VLAN_INSERT |
253 DEV_TX_OFFLOAD_IPV4_CKSUM |
254 DEV_TX_OFFLOAD_UDP_CKSUM |
255 DEV_TX_OFFLOAD_TCP_CKSUM |
256 DEV_TX_OFFLOAD_SCTP_CKSUM |
257 DEV_TX_OFFLOAD_TCP_TSO,
261 ret = rte_eth_dev_configure(port_id, nr_queues, nr_queues, &port_conf);
263 rte_exit(EXIT_FAILURE,
264 ":: cannot configure device: err=%d, port=%u\n",
267 rte_eth_dev_info_get(port_id, &dev_info);
268 rxq_conf = dev_info.default_rxconf;
269 rxq_conf.offloads = port_conf.rxmode.offloads;
271 For this example we are configuring number of rx and tx queues that are connected
276 for (i = 0; i < nr_queues; i++) {
277 ret = rte_eth_rx_queue_setup(port_id, i, 512,
278 rte_eth_dev_socket_id(port_id),
282 rte_exit(EXIT_FAILURE,
283 ":: Rx queue setup failed: err=%d, port=%u\n",
288 for (i = 0; i < nr_queues; i++) {
289 ret = rte_eth_tx_queue_setup(port_id, i, 512,
290 rte_eth_dev_socket_id(port_id),
293 rte_exit(EXIT_FAILURE,
294 ":: Tx queue setup failed: err=%d, port=%u\n",
299 In the next step we create and apply the flow rule. which is to send packets
300 with destination ip equals to 192.168.1.1 to queue number 1. The detail
301 explanation of the ``generate_ipv4_flow()`` appears later in this document:
305 flow = generate_ipv4_flow(port_id, selected_queue,
307 DEST_IP, FULL_MASK, &error);
309 We are setting the RX port to promiscuous mode:
313 rte_eth_promiscuous_enable(port_id);
315 The last step is to start the port.
319 ret = rte_eth_dev_start(port_id);
321 rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err%d, port=%u\n",
326 The main_loop function
327 ~~~~~~~~~~~~~~~~~~~~~~
329 As we saw above the ``main()`` function calls an application function to handle
330 the main loop. For the flow filtering application the main_loop function
331 looks like the following:
338 struct rte_mbuf *mbufs[32];
339 struct ether_hdr *eth_hdr;
344 while (!force_quit) {
345 for (i = 0; i < nr_queues; i++) {
346 nb_rx = rte_eth_rx_burst(port_id,
349 for (j = 0; j < nb_rx; j++) {
350 struct rte_mbuf *m = mbufs[j];
352 eth_hdr = rte_pktmbuf_mtod(m,
354 print_ether_addr("src=",
356 print_ether_addr(" - dst=",
358 printf(" - queue=0x%x",
366 /* closing and releasing resources */
367 rte_flow_flush(port_id, &error);
368 rte_eth_dev_stop(port_id);
369 rte_eth_dev_close(port_id);
372 The main work of the application is reading the packets from all
373 queues and printing for each packet the destination queue:
377 while (!force_quit) {
378 for (i = 0; i < nr_queues; i++) {
379 nb_rx = rte_eth_rx_burst(port_id, i, mbufs, 32);
381 for (j = 0; j < nb_rx; j++) {
382 struct rte_mbuf *m = mbufs[j];
383 eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
384 print_ether_addr("src=", ð_hdr->s_addr);
385 print_ether_addr(" - dst=", ð_hdr->d_addr);
386 printf(" - queue=0x%x", (unsigned int)i);
395 The forwarding loop can be interrupted and the application closed using
396 ``Ctrl-C``. Which results in closing the port and the device using
397 ``rte_eth_dev_stop`` and ``rte_eth_dev_close``
399 The generate_ipv4_flow function
400 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
402 The generate_ipv4_rule function is responsible for creating the flow rule.
403 This function is located in the ``flow_blocks.c`` file.
407 static struct rte_flow *
408 generate_ipv4_flow(uint8_t port_id, uint16_t rx_q,
409 uint32_t src_ip, uint32_t src_mask,
410 uint32_t dest_ip, uint32_t dest_mask,
411 struct rte_flow_error *error)
413 struct rte_flow_attr attr;
414 struct rte_flow_item pattern[MAX_PATTERN_NUM];
415 struct rte_flow_action action[MAX_PATTERN_NUM];
416 struct rte_flow *flow = NULL;
417 struct rte_flow_action_queue queue = { .index = rx_q };
418 struct rte_flow_item_eth eth_spec;
419 struct rte_flow_item_eth eth_mask;
420 struct rte_flow_item_vlan vlan_spec;
421 struct rte_flow_item_vlan vlan_mask;
422 struct rte_flow_item_ipv4 ip_spec;
423 struct rte_flow_item_ipv4 ip_mask;
425 memset(pattern, 0, sizeof(pattern));
426 memset(action, 0, sizeof(action));
429 * set the rule attribute.
430 * in this case only ingress packets will be checked.
432 memset(&attr, 0, sizeof(struct rte_flow_attr));
436 * create the action sequence.
437 * one action only, move packet to queue
440 action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
441 action[0].conf = &queue;
442 action[1].type = RTE_FLOW_ACTION_TYPE_END;
445 * set the first level of the pattern (eth).
446 * since in this example we just want to get the
447 * ipv4 we set this level to allow all.
449 memset(ð_spec, 0, sizeof(struct rte_flow_item_eth));
450 memset(ð_mask, 0, sizeof(struct rte_flow_item_eth));
453 pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
454 pattern[0].spec = ð_spec;
455 pattern[0].mask = ð_mask;
458 * setting the second level of the pattern (vlan).
459 * since in this example we just want to get the
460 * ipv4 we also set this level to allow all.
462 memset(&vlan_spec, 0, sizeof(struct rte_flow_item_vlan));
463 memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
464 pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
465 pattern[1].spec = &vlan_spec;
466 pattern[1].mask = &vlan_mask;
469 * setting the third level of the pattern (ip).
470 * in this example this is the level we care about
471 * so we set it according to the parameters.
473 memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4));
474 memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4));
475 ip_spec.hdr.dst_addr = htonl(dest_ip);
476 ip_mask.hdr.dst_addr = dest_mask;
477 ip_spec.hdr.src_addr = htonl(src_ip);
478 ip_mask.hdr.src_addr = src_mask;
479 pattern[2].type = RTE_FLOW_ITEM_TYPE_IPV4;
480 pattern[2].spec = &ip_spec;
481 pattern[2].mask = &ip_mask;
483 /* the final level must be always type end */
484 pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
486 int res = rte_flow_validate(port_id, &attr, pattern, action, error);
488 flow = rte_flow_create(port_id, &attr, pattern, action, error);
493 The first part of the function is declaring the structures that will be used.
497 struct rte_flow_attr attr;
498 struct rte_flow_item pattern[MAX_PATTERN_NUM];
499 struct rte_flow_action action[MAX_PATTERN_NUM];
500 struct rte_flow *flow;
501 struct rte_flow_error error;
502 struct rte_flow_action_queue queue = { .index = rx_q };
503 struct rte_flow_item_eth eth_spec;
504 struct rte_flow_item_eth eth_mask;
505 struct rte_flow_item_vlan vlan_spec;
506 struct rte_flow_item_vlan vlan_mask;
507 struct rte_flow_item_ipv4 ip_spec;
508 struct rte_flow_item_ipv4 ip_mask;
510 The following part create the flow attributes, in our case ingress.
514 memset(&attr, 0, sizeof(struct rte_flow_attr));
517 The third part defines the action to be taken when a packet matches
518 the rule. In this case send the packet to queue.
522 action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
523 action[0].conf = &queue;
524 action[1].type = RTE_FLOW_ACTION_TYPE_END;
526 The forth part is responsible for creating the pattern and is build from
527 number of step. In each step we build one level of the pattern starting with
530 Setting the first level of the pattern ETH:
534 memset(ð_spec, 0, sizeof(struct rte_flow_item_eth));
535 memset(ð_mask, 0, sizeof(struct rte_flow_item_eth));
538 pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
539 pattern[0].spec = ð_spec;
540 pattern[0].mask = ð_mask;
542 Setting the second level of the pattern VLAN:
546 memset(&vlan_spec, 0, sizeof(struct rte_flow_item_vlan));
547 memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
548 pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
549 pattern[1].spec = &vlan_spec;
550 pattern[1].mask = &vlan_mask;
552 Setting the third level ip:
556 memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4));
557 memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4));
558 ip_spec.hdr.dst_addr = htonl(dest_ip);
559 ip_mask.hdr.dst_addr = dest_mask;
560 ip_spec.hdr.src_addr = htonl(src_ip);
561 ip_mask.hdr.src_addr = src_mask;
562 pattern[2].type = RTE_FLOW_ITEM_TYPE_IPV4;
563 pattern[2].spec = &ip_spec;
564 pattern[2].mask = &ip_mask;
566 Closing the pattern part.
570 pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
572 The last part of the function is to validate the rule and create it.
576 int res = rte_flow_validate(port_id, &attr, pattern, action, &error);
578 flow = rte_flow_create(port_id, &attr, pattern, action, &error);