-.. BSD LICENSE
- Copyright(c) 2017 Mellanox Corporation. All rights reserved.
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- * Neither the name of Mellanox Corporation nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
+.. SPDX-License-Identifier: BSD-3-Clause
+ Copyright 2017 Mellanox Technologies, Ltd
Basic RTE Flow Filtering Sample Application
===========================================
Compiling the Application
-------------------------
-To compile the application export the path to the DPDK source tree and go to
-the example directory:
-
-.. code-block:: console
-
- export RTE_SDK=/path/to/rte_sdk
-
- cd ${RTE_SDK}/examples/flow_filtering
-
-Set the target, for example:
-
-.. code-block:: console
-
- export RTE_TARGET=x86_64-native-linuxapp-gcc
-
-See the *DPDK Getting Started* Guide for possible ``RTE_TARGET`` values.
-
-Build the application as follows:
-
-.. code-block:: console
-
- make
+To compile the sample application see :doc:`compiling`.
Running the Application
-----------------------
-To run the example in a ``linuxapp`` environment:
+To run the example in a ``linux`` environment:
.. code-block:: console
- ./build/flow -l 1 -n 1
+ ./<build_dir>/examples/dpdk-flow_filtering -l 1 -n 1
Refer to *DPDK Getting Started Guide* for general information on running
applications and the Environment Abstraction Layer (EAL) options.
Explanation
-----------
-The example is build from 2 main files,
+The example is built from 2 files,
``main.c`` which holds the example logic and ``flow_blocks.c`` that holds the
implementation for building the flow rule.
struct rte_eth_conf port_conf = {
.rxmode = {
.split_hdr_size = 0,
- /**< Header Split disabled */
- .header_split = 0,
- /**< IP checksum offload disabled */
- .hw_ip_checksum = 0,
- /**< VLAN filtering disabled */
- .hw_vlan_filter = 0,
- /**< Jumbo Frame Support disabled */
- .jumbo_frame = 0,
- /**< CRC stripped by hardware */
- .hw_strip_crc = 1,
+ },
+ .txmode = {
+ .offloads =
+ DEV_TX_OFFLOAD_VLAN_INSERT |
+ DEV_TX_OFFLOAD_IPV4_CKSUM |
+ DEV_TX_OFFLOAD_UDP_CKSUM |
+ DEV_TX_OFFLOAD_TCP_CKSUM |
+ DEV_TX_OFFLOAD_SCTP_CKSUM |
+ DEV_TX_OFFLOAD_TCP_TSO,
},
};
+ struct rte_eth_txconf txq_conf;
+ struct rte_eth_rxconf rxq_conf;
+ struct rte_eth_dev_info dev_info;
printf(":: initializing port: %d\n", port_id);
ret = rte_eth_dev_configure(port_id,
- nr_queues, nr_queues, &port_conf);
+ nr_queues, nr_queues, &port_conf);
if (ret < 0) {
rte_exit(EXIT_FAILURE,
":: cannot configure device: err=%d, port=%u\n",
ret, port_id);
}
+ rte_eth_dev_info_get(port_id, &dev_info);
+ rxq_conf = dev_info.default_rxconf;
+ rxq_conf.offloads = port_conf.rxmode.offloads;
/* only set Rx queues: something we care only so far */
for (i = 0; i < nr_queues; i++) {
ret = rte_eth_rx_queue_setup(port_id, i, 512,
- rte_eth_dev_socket_id(port_id),
- NULL,
- mbuf_pool);
+ rte_eth_dev_socket_id(port_id),
+ &rxq_conf,
+ mbuf_pool);
if (ret < 0) {
- rte_exit(EXIT_FAILURE,
- ":: Rx queue setup failed: err=%d, port=%u\n",
- ret, port_id);
+ rte_exit(EXIT_FAILURE,
+ ":: Rx queue setup failed: err=%d, port=%u\n",
+ ret, port_id);
}
}
+ txq_conf = dev_info.default_txconf;
+ txq_conf.offloads = port_conf.txmode.offloads;
+
+ for (i = 0; i < nr_queues; i++) {
+ ret = rte_eth_tx_queue_setup(port_id, i, 512,
+ rte_eth_dev_socket_id(port_id),
+ &txq_conf);
+ if (ret < 0) {
+ rte_exit(EXIT_FAILURE,
+ ":: Tx queue setup failed: err=%d, port=%u\n",
+ ret, port_id);
+ }
+ }
- rte_eth_promiscuous_enable(port_id);
+ ret = rte_eth_promiscuous_enable(port_id);
+ if (ret != 0) {
+ rte_exit(EXIT_FAILURE,
+ ":: cannot enable promiscuous mode: err=%d, port=%u\n",
+ ret, port_id);
+ }
ret = rte_eth_dev_start(port_id);
if (ret < 0) {
.. code-block:: c
struct rte_eth_conf port_conf = {
- .rxmode = {
- .split_hdr_size = 0,
- /**< Header Split disabled */
- .header_split = 0,
- /**< IP checksum offload disabled */
- .hw_ip_checksum = 0,
- /**< VLAN filtering disabled */
- .hw_vlan_filter = 0,
- /**< Jumbo Frame Support disabled */
- .jumbo_frame = 0,
- /**< CRC stripped by hardware */
- .hw_strip_crc = 1,
- },
- };
+ .rxmode = {
+ .split_hdr_size = 0,
+ },
+ .txmode = {
+ .offloads =
+ DEV_TX_OFFLOAD_VLAN_INSERT |
+ DEV_TX_OFFLOAD_IPV4_CKSUM |
+ DEV_TX_OFFLOAD_UDP_CKSUM |
+ DEV_TX_OFFLOAD_TCP_CKSUM |
+ DEV_TX_OFFLOAD_SCTP_CKSUM |
+ DEV_TX_OFFLOAD_TCP_TSO,
+ },
+ };
ret = rte_eth_dev_configure(port_id, nr_queues, nr_queues, &port_conf);
if (ret < 0) {
":: cannot configure device: err=%d, port=%u\n",
ret, port_id);
}
+ rte_eth_dev_info_get(port_id, &dev_info);
+ rxq_conf = dev_info.default_rxconf;
+ rxq_conf.offloads = port_conf.rxmode.offloads;
-For this example we are configuring number of rx queues that are connected to
-a single port.
+For this example we are configuring number of rx and tx queues that are connected
+to a single port.
.. code-block:: c
for (i = 0; i < nr_queues; i++) {
ret = rte_eth_rx_queue_setup(port_id, i, 512,
rte_eth_dev_socket_id(port_id),
- NULL,
+ &rxq_conf,
mbuf_pool);
if (ret < 0) {
rte_exit(EXIT_FAILURE,
":: Rx queue setup failed: err=%d, port=%u\n",
ret, port_id);
}
- }
+ }
+
+ for (i = 0; i < nr_queues; i++) {
+ ret = rte_eth_tx_queue_setup(port_id, i, 512,
+ rte_eth_dev_socket_id(port_id),
+ &txq_conf);
+ if (ret < 0) {
+ rte_exit(EXIT_FAILURE,
+ ":: Tx queue setup failed: err=%d, port=%u\n",
+ ret, port_id);
+ }
+ }
In the next step we create and apply the flow rule. which is to send packets
with destination ip equals to 192.168.1.1 to queue number 1. The detail
.. code-block:: c
- rte_eth_promiscuous_enable(port_id);
+ ret = rte_eth_promiscuous_enable(port_id);
+ if (ret != 0) {
+ rte_exit(EXIT_FAILURE,
+ ":: cannot enable promiscuous mode: err=%d, port=%u\n",
+ ret, port_id);
+ }
The last step is to start the port.
main_loop(void)
{
struct rte_mbuf *mbufs[32];
- struct ether_hdr *eth_hdr;
+ struct rte_ether_hdr *eth_hdr;
uint16_t nb_rx;
uint16_t i;
uint16_t j;
struct rte_mbuf *m = mbufs[j];
eth_hdr = rte_pktmbuf_mtod(m,
- struct ether_hdr *);
+ struct rte_ether_hdr *);
print_ether_addr("src=",
ð_hdr->s_addr);
print_ether_addr(" - dst=",
if (nb_rx) {
for (j = 0; j < nb_rx; j++) {
struct rte_mbuf *m = mbufs[j];
- eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
+ eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
print_ether_addr("src=", ð_hdr->s_addr);
print_ether_addr(" - dst=", ð_hdr->d_addr);
printf(" - queue=0x%x", (unsigned int)i);
The generate_ipv4_flow function
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The generate_ipv4_rule function is responsible for creating the flow rule.
+The generate_ipv4_flow function is responsible for creating the flow rule.
This function is located in the ``flow_blocks.c`` file.
.. code-block:: c
static struct rte_flow *
- generate_ipv4_flow(uint8_t port_id, uint16_t rx_q,
+ generate_ipv4_flow(uint16_t port_id, uint16_t rx_q,
uint32_t src_ip, uint32_t src_mask,
uint32_t dest_ip, uint32_t dest_mask,
struct rte_flow_error *error)
{
struct rte_flow_attr attr;
struct rte_flow_item pattern[MAX_PATTERN_NUM];
- struct rte_flow_action action[MAX_PATTERN_NUM];
+ struct rte_flow_action action[MAX_ACTION_NUM];
struct rte_flow *flow = NULL;
struct rte_flow_action_queue queue = { .index = rx_q };
- struct rte_flow_item_eth eth_spec;
- struct rte_flow_item_eth eth_mask;
- struct rte_flow_item_vlan vlan_spec;
- struct rte_flow_item_vlan vlan_mask;
struct rte_flow_item_ipv4 ip_spec;
struct rte_flow_item_ipv4 ip_mask;
* create the action sequence.
* one action only, move packet to queue
*/
-
action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
action[0].conf = &queue;
action[1].type = RTE_FLOW_ACTION_TYPE_END;
/*
- * set the first level of the pattern (eth).
+ * set the first level of the pattern (ETH).
* since in this example we just want to get the
* ipv4 we set this level to allow all.
*/
- memset(ð_spec, 0, sizeof(struct rte_flow_item_eth));
- memset(ð_mask, 0, sizeof(struct rte_flow_item_eth));
- eth_spec.type = 0;
- eth_mask.type = 0;
pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
- pattern[0].spec = ð_spec;
- pattern[0].mask = ð_mask;
-
- /*
- * setting the second level of the pattern (vlan).
- * since in this example we just want to get the
- * ipv4 we also set this level to allow all.
- */
- memset(&vlan_spec, 0, sizeof(struct rte_flow_item_vlan));
- memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
- pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
- pattern[1].spec = &vlan_spec;
- pattern[1].mask = &vlan_mask;
/*
- * setting the third level of the pattern (ip).
+ * setting the second level of the pattern (IP).
* in this example this is the level we care about
* so we set it according to the parameters.
*/
ip_mask.hdr.dst_addr = dest_mask;
ip_spec.hdr.src_addr = htonl(src_ip);
ip_mask.hdr.src_addr = src_mask;
- pattern[2].type = RTE_FLOW_ITEM_TYPE_IPV4;
- pattern[2].spec = &ip_spec;
- pattern[2].mask = &ip_mask;
+ pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+ pattern[1].spec = &ip_spec;
+ pattern[1].mask = &ip_mask;
/* the final level must be always type end */
- pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+ pattern[2].type = RTE_FLOW_ITEM_TYPE_END;
int res = rte_flow_validate(port_id, &attr, pattern, action, error);
if(!res)
struct rte_flow_attr attr;
struct rte_flow_item pattern[MAX_PATTERN_NUM];
- struct rte_flow_action action[MAX_PATTERN_NUM];
+ struct rte_flow_action action[MAX_ACTION_NUM];
struct rte_flow *flow;
struct rte_flow_error error;
struct rte_flow_action_queue queue = { .index = rx_q };
- struct rte_flow_item_eth eth_spec;
- struct rte_flow_item_eth eth_mask;
- struct rte_flow_item_vlan vlan_spec;
- struct rte_flow_item_vlan vlan_mask;
struct rte_flow_item_ipv4 ip_spec;
struct rte_flow_item_ipv4 ip_mask;
action[0].conf = &queue;
action[1].type = RTE_FLOW_ACTION_TYPE_END;
-The forth part is responsible for creating the pattern and is build from
-number of step. In each step we build one level of the pattern starting with
+The fourth part is responsible for creating the pattern and is built from
+number of steps. In each step we build one level of the pattern starting with
the lowest one.
Setting the first level of the pattern ETH:
.. code-block:: c
- memset(ð_spec, 0, sizeof(struct rte_flow_item_eth));
- memset(ð_mask, 0, sizeof(struct rte_flow_item_eth));
- eth_spec.type = 0;
- eth_mask.type = 0;
pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
- pattern[0].spec = ð_spec;
- pattern[0].mask = ð_mask;
-
-Setting the second level of the pattern VLAN:
-
-.. code-block:: c
-
- memset(&vlan_spec, 0, sizeof(struct rte_flow_item_vlan));
- memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
- pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
- pattern[1].spec = &vlan_spec;
- pattern[1].mask = &vlan_mask;
-Setting the third level ip:
+Setting the second level of the pattern IP:
.. code-block:: c
ip_mask.hdr.dst_addr = dest_mask;
ip_spec.hdr.src_addr = htonl(src_ip);
ip_mask.hdr.src_addr = src_mask;
- pattern[2].type = RTE_FLOW_ITEM_TYPE_IPV4;
- pattern[2].spec = &ip_spec;
- pattern[2].mask = &ip_mask;
+ pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+ pattern[1].spec = &ip_spec;
+ pattern[1].mask = &ip_mask;
Closing the pattern part.
.. code-block:: c
- pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+ pattern[2].type = RTE_FLOW_ITEM_TYPE_END;
The last part of the function is to validate the rule and create it.
int res = rte_flow_validate(port_id, &attr, pattern, action, &error);
if (!res)
flow = rte_flow_create(port_id, &attr, pattern, action, &error);
-