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 /**< Header Split disabled */
172 /**< IP checksum offload disabled */
174 /**< VLAN filtering disabled */
176 /**< Jumbo Frame Support disabled */
178 /**< CRC stripped by hardware */
183 printf(":: initializing port: %d\n", port_id);
184 ret = rte_eth_dev_configure(port_id,
185 nr_queues, nr_queues, &port_conf);
187 rte_exit(EXIT_FAILURE,
188 ":: cannot configure device: err=%d, port=%u\n",
192 /* only set Rx queues: something we care only so far */
193 for (i = 0; i < nr_queues; i++) {
194 ret = rte_eth_rx_queue_setup(port_id, i, 512,
195 rte_eth_dev_socket_id(port_id),
199 rte_exit(EXIT_FAILURE,
200 ":: Rx queue setup failed: err=%d, port=%u\n",
206 rte_eth_promiscuous_enable(port_id);
208 ret = rte_eth_dev_start(port_id);
210 rte_exit(EXIT_FAILURE,
211 "rte_eth_dev_start:err=%d, port=%u\n",
215 assert_link_status();
217 printf(":: initializing port: %d done\n", port_id);
220 The Ethernet port is configured with default settings using the
221 ``rte_eth_dev_configure()`` function and the ``port_conf_default`` struct:
225 struct rte_eth_conf port_conf = {
228 /**< Header Split disabled */
230 /**< IP checksum offload disabled */
232 /**< VLAN filtering disabled */
234 /**< Jumbo Frame Support disabled */
236 /**< CRC stripped by hardware */
241 ret = rte_eth_dev_configure(port_id, nr_queues, nr_queues, &port_conf);
243 rte_exit(EXIT_FAILURE,
244 ":: cannot configure device: err=%d, port=%u\n",
248 For this example we are configuring number of rx queues that are connected to
253 for (i = 0; i < nr_queues; i++) {
254 ret = rte_eth_rx_queue_setup(port_id, i, 512,
255 rte_eth_dev_socket_id(port_id),
259 rte_exit(EXIT_FAILURE,
260 ":: Rx queue setup failed: err=%d, port=%u\n",
265 In the next step we create and apply the flow rule. which is to send packets
266 with destination ip equals to 192.168.1.1 to queue number 1. The detail
267 explanation of the ``generate_ipv4_flow()`` appears later in this document:
271 flow = generate_ipv4_flow(port_id, selected_queue,
273 DEST_IP, FULL_MASK, &error);
275 We are setting the RX port to promiscuous mode:
279 rte_eth_promiscuous_enable(port_id);
281 The last step is to start the port.
285 ret = rte_eth_dev_start(port_id);
287 rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err%d, port=%u\n",
292 The main_loop function
293 ~~~~~~~~~~~~~~~~~~~~~~
295 As we saw above the ``main()`` function calls an application function to handle
296 the main loop. For the flow filtering application the main_loop function
297 looks like the following:
304 struct rte_mbuf *mbufs[32];
305 struct ether_hdr *eth_hdr;
310 while (!force_quit) {
311 for (i = 0; i < nr_queues; i++) {
312 nb_rx = rte_eth_rx_burst(port_id,
315 for (j = 0; j < nb_rx; j++) {
316 struct rte_mbuf *m = mbufs[j];
318 eth_hdr = rte_pktmbuf_mtod(m,
320 print_ether_addr("src=",
322 print_ether_addr(" - dst=",
324 printf(" - queue=0x%x",
332 /* closing and releasing resources */
333 rte_flow_flush(port_id, &error);
334 rte_eth_dev_stop(port_id);
335 rte_eth_dev_close(port_id);
338 The main work of the application is reading the packets from all
339 queues and printing for each packet the destination queue:
343 while (!force_quit) {
344 for (i = 0; i < nr_queues; i++) {
345 nb_rx = rte_eth_rx_burst(port_id, i, mbufs, 32);
347 for (j = 0; j < nb_rx; j++) {
348 struct rte_mbuf *m = mbufs[j];
349 eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
350 print_ether_addr("src=", ð_hdr->s_addr);
351 print_ether_addr(" - dst=", ð_hdr->d_addr);
352 printf(" - queue=0x%x", (unsigned int)i);
361 The forwarding loop can be interrupted and the application closed using
362 ``Ctrl-C``. Which results in closing the port and the device using
363 ``rte_eth_dev_stop`` and ``rte_eth_dev_close``
365 The generate_ipv4_flow function
366 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
368 The generate_ipv4_rule function is responsible for creating the flow rule.
369 This function is located in the ``flow_blocks.c`` file.
373 static struct rte_flow *
374 generate_ipv4_flow(uint8_t port_id, uint16_t rx_q,
375 uint32_t src_ip, uint32_t src_mask,
376 uint32_t dest_ip, uint32_t dest_mask,
377 struct rte_flow_error *error)
379 struct rte_flow_attr attr;
380 struct rte_flow_item pattern[MAX_PATTERN_NUM];
381 struct rte_flow_action action[MAX_PATTERN_NUM];
382 struct rte_flow *flow = NULL;
383 struct rte_flow_action_queue queue = { .index = rx_q };
384 struct rte_flow_item_eth eth_spec;
385 struct rte_flow_item_eth eth_mask;
386 struct rte_flow_item_vlan vlan_spec;
387 struct rte_flow_item_vlan vlan_mask;
388 struct rte_flow_item_ipv4 ip_spec;
389 struct rte_flow_item_ipv4 ip_mask;
391 memset(pattern, 0, sizeof(pattern));
392 memset(action, 0, sizeof(action));
395 * set the rule attribute.
396 * in this case only ingress packets will be checked.
398 memset(&attr, 0, sizeof(struct rte_flow_attr));
402 * create the action sequence.
403 * one action only, move packet to queue
406 action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
407 action[0].conf = &queue;
408 action[1].type = RTE_FLOW_ACTION_TYPE_END;
411 * set the first level of the pattern (eth).
412 * since in this example we just want to get the
413 * ipv4 we set this level to allow all.
415 memset(ð_spec, 0, sizeof(struct rte_flow_item_eth));
416 memset(ð_mask, 0, sizeof(struct rte_flow_item_eth));
419 pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
420 pattern[0].spec = ð_spec;
421 pattern[0].mask = ð_mask;
424 * setting the second level of the pattern (vlan).
425 * since in this example we just want to get the
426 * ipv4 we also set this level to allow all.
428 memset(&vlan_spec, 0, sizeof(struct rte_flow_item_vlan));
429 memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
430 pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
431 pattern[1].spec = &vlan_spec;
432 pattern[1].mask = &vlan_mask;
435 * setting the third level of the pattern (ip).
436 * in this example this is the level we care about
437 * so we set it according to the parameters.
439 memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4));
440 memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4));
441 ip_spec.hdr.dst_addr = htonl(dest_ip);
442 ip_mask.hdr.dst_addr = dest_mask;
443 ip_spec.hdr.src_addr = htonl(src_ip);
444 ip_mask.hdr.src_addr = src_mask;
445 pattern[2].type = RTE_FLOW_ITEM_TYPE_IPV4;
446 pattern[2].spec = &ip_spec;
447 pattern[2].mask = &ip_mask;
449 /* the final level must be always type end */
450 pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
452 int res = rte_flow_validate(port_id, &attr, pattern, action, error);
454 flow = rte_flow_create(port_id, &attr, pattern, action, error);
459 The first part of the function is declaring the structures that will be used.
463 struct rte_flow_attr attr;
464 struct rte_flow_item pattern[MAX_PATTERN_NUM];
465 struct rte_flow_action action[MAX_PATTERN_NUM];
466 struct rte_flow *flow;
467 struct rte_flow_error error;
468 struct rte_flow_action_queue queue = { .index = rx_q };
469 struct rte_flow_item_eth eth_spec;
470 struct rte_flow_item_eth eth_mask;
471 struct rte_flow_item_vlan vlan_spec;
472 struct rte_flow_item_vlan vlan_mask;
473 struct rte_flow_item_ipv4 ip_spec;
474 struct rte_flow_item_ipv4 ip_mask;
476 The following part create the flow attributes, in our case ingress.
480 memset(&attr, 0, sizeof(struct rte_flow_attr));
483 The third part defines the action to be taken when a packet matches
484 the rule. In this case send the packet to queue.
488 action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
489 action[0].conf = &queue;
490 action[1].type = RTE_FLOW_ACTION_TYPE_END;
492 The forth part is responsible for creating the pattern and is build from
493 number of step. In each step we build one level of the pattern starting with
496 Setting the first level of the pattern ETH:
500 memset(ð_spec, 0, sizeof(struct rte_flow_item_eth));
501 memset(ð_mask, 0, sizeof(struct rte_flow_item_eth));
504 pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
505 pattern[0].spec = ð_spec;
506 pattern[0].mask = ð_mask;
508 Setting the second level of the pattern VLAN:
512 memset(&vlan_spec, 0, sizeof(struct rte_flow_item_vlan));
513 memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
514 pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
515 pattern[1].spec = &vlan_spec;
516 pattern[1].mask = &vlan_mask;
518 Setting the third level ip:
522 memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4));
523 memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4));
524 ip_spec.hdr.dst_addr = htonl(dest_ip);
525 ip_mask.hdr.dst_addr = dest_mask;
526 ip_spec.hdr.src_addr = htonl(src_ip);
527 ip_mask.hdr.src_addr = src_mask;
528 pattern[2].type = RTE_FLOW_ITEM_TYPE_IPV4;
529 pattern[2].spec = &ip_spec;
530 pattern[2].mask = &ip_mask;
532 Closing the pattern part.
536 pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
538 The last part of the function is to validate the rule and create it.
542 int res = rte_flow_validate(port_id, &attr, pattern, action, &error);
544 flow = rte_flow_create(port_id, &attr, pattern, action, &error);