From patchwork Thu Oct 19 10:16:07 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ori Kam X-Patchwork-Id: 30580 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id C297E1B1C5; Thu, 19 Oct 2017 12:16:25 +0200 (CEST) Received: from EUR03-AM5-obe.outbound.protection.outlook.com (mail-eopbgr30047.outbound.protection.outlook.com [40.107.3.47]) by dpdk.org (Postfix) with ESMTP id 77FDA1B1C1 for ; Thu, 19 Oct 2017 12:16:24 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Mellanox.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=9OD/yZyKKVkaeIK2CkBZnL/WyGQP2DAUHdlkFOoArEw=; b=aCp1pkErX3b22x9HP4l2W+F7g5sPJSw/etJ8p2z+VQYCoTIQid8VtQZVCN/MD9HYBbLQG5uq9MsTVXb4X1UucIfmQMXtRpBzrNxudV9k9n7hFdnxj/OyHXq6DKprQ6sF7tG6Yz/vNzCsm1sDjPoFb58ry0DW7xlVq6SygNXfyVg= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=orika@mellanox.com; Received: from localhost.localdomain (82.166.227.17) by HE1PR05MB3210.eurprd05.prod.outlook.com (2603:10a6:7:36::32) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.77.7; Thu, 19 Oct 2017 10:16:21 +0000 From: Ori Kam To: adrien.mazarguil@6wind.com, john.mcnamara@intel.com, thomas@monjalon.net Cc: dev@dpdk.org, orika@mellanox.com Date: Thu, 19 Oct 2017 13:16:07 +0300 Message-Id: <1508408167-9001-1-git-send-email-orika@mellanox.com> X-Mailer: git-send-email 1.7.1 MIME-Version: 1.0 X-Originating-IP: [82.166.227.17] X-ClientProxiedBy: AM5PR0102CA0012.eurprd01.prod.exchangelabs.com (2603:10a6:206::25) To HE1PR05MB3210.eurprd05.prod.outlook.com (2603:10a6:7:36::32) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 74f2cf05-bf58-4409-c315-08d516da7298 X-MS-Office365-Filtering-HT: Tenant X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(22001)(2017030254152)(48565401081)(2017052603199)(201703131423075)(201703031133081)(201702281549075); SRVR:HE1PR05MB3210; X-Microsoft-Exchange-Diagnostics: 1; HE1PR05MB3210; 3:glsBlKZgH0bhIFYPQ41aBMnTFLZOYLeTsloJtRS1qaa+KFRCDmotcqSctxv4gRcweZ4/WVDpd/hiwMHT8uNO17lDrhEWEOVOcbeqf11YzTwkzQr0zsu4gOCdW4IPt1cnnbejLrrQVlHTayJe8kN/NSEhVF+dFzZPV6hu2W2LI7395s8NIcfwszfCIgGUFl0I0mW6pI3bjRWZB9tM7e7v8v2yPZFZhV6ikQfdTW+L2FwDgfn2fpUiQfpSC+w7YUUU; 25:0KBv+daYqdH9PAtyMLG37r+3dRrghVkbzb34hHU/c+1sCTCtoZFQD/Uxfs0XEQSAa0x0eKQnaHVTLzSDtwUPqDeNveAdWSpq2LbcUHKYUS1nSTeK+qx0lN3o2Hyz6gyabdNy6hjv4NMGy1H4P5UwDzJPyWSGr7TgKT4z4u8tZ8u0Km7JK5LBBNVhzl2r3gsg7q6FtynpjwjBtBn26gBmWlFjHy+Sm1kpHEd8fUWfeFW09BM8Isfexsbj81OptVVkyr5NSGtoAn0MaQd5/uZeDx6xECe9oQUQlJ9SqWoAhEGdfPqXQk39JhVH8sQGyaCA1SiqoZqPVhZoFqZd8wzZq+PuNRli7liNausVdgVdoDQ=; 31:U/c7O5BiGhm/BmgcdfDOWA/nfEGW5YGRqqkXSlqxPreWziLJXzIao+FKoDEIvAgzo2Ys5nvyHHFgLFYaE3ADtXVyC2/iYTaub5BvI6SUIo8EmrXPX3pvbt/ID6FGwj0eIsatlCZWhXBa4wKNg+XEL148DT1jOYYInhPslVvEvCBP2B0L066dMGJLzYNl4wRC4LqkI3AQ8QNNlcX6r3sKJh/msoc+SDwyM+TViik1ph4= X-MS-TrafficTypeDiagnostic: HE1PR05MB3210: X-LD-Processed: a652971c-7d2e-4d9b-a6a4-d149256f461b,ExtAddr X-Microsoft-Exchange-Diagnostics: 1; HE1PR05MB3210; 20:sx8FRXwCWlM+le8NZAqZt2psvOxB00ywZV/NO2LYBnQmK5mhEVprI95/jaEaOf2xL13lOpS5StSJAJwLumX0TBgMIL0S3oog9JbK44ExBsVXt3z+0qHljeTShFfesbHYIt+8XNLY3g8wANG/DzVpG0duJtmyYCoiuHUXpexirTTeje6haBZCk15kVzHNAqrFaD073b0kPaoIK44WG68dLp754bioBn3opBQM6APWG7zUgT6eFnlHHWEZZ3wkplNRmoMfk6fbrb4TW5Xvdtv3UefM0Cygh53o27XLO0R+9JLIl2I2iN6FTY53ZyrWE/rTHp/oPgzHKIFSQDN4TsCZ2Ps8/8mH6NCdfnEXV0/izbsFk345DZS1irba9iFyIRH6hXB496PU7lOVEfmpT1UD0anbWPbcurI1umGwYtEbTbgWH71xsnVLPFWF2/CX+JoQv+xzYMde7ZdC5v41lU60O79Npo5akHqwQIeOrOjFxcrlWN4gJe+UNdhkKidDyDid; 4:Ymx3p/rpeIVftHlSulKnBWPHq6ZvpCPHJ/JhH3zJv1D5nVB0X17QWwXC4N1BXSdL5gr/681aUzInsN8crOC0pASh50dZnL1j0/qDgCNesgJABHMOwiLnVOJo2Els3/ImFZPxDvaGAmKBPWLI898mYtYfly/LNz1kZb66MIUJoHrsdCCw/84++KwitJVVJWxcVGPqL0zr/UEnXK9iUeJ67Fm6xKi2HfZzCvr6AKsNebWVHkq8ZXvDqpLOFpjaTduPB7d/YYhIC5RFxPnk4JEUXUa5F4UawWn7Iz7Fb9Ii/H8= X-Exchange-Antispam-Report-Test: UriScan:(116097685857584); X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(6040450)(2401047)(5005006)(8121501046)(10201501046)(100000703101)(100105400095)(93006095)(93001095)(3002001)(6055026)(6041248)(20161123560025)(20161123555025)(20161123558100)(20161123562025)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(20161123564025)(6072148)(201708071742011)(100000704101)(100105200095)(100000705101)(100105500095); SRVR:HE1PR05MB3210; BCL:0; PCL:0; RULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095); SRVR:HE1PR05MB3210; X-Forefront-PRVS: 0465429B7F X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(6009001)(6069001)(376002)(39860400002)(346002)(189002)(199003)(51234002)(86362001)(16586007)(316002)(36756003)(68736007)(6512007)(107886003)(16526018)(53936002)(6666003)(5660300001)(97736004)(5003940100001)(33646002)(4326008)(3846002)(6116002)(8676002)(81156014)(81166006)(478600001)(6486002)(50986999)(101416001)(6506006)(305945005)(7736002)(25786009)(50466002)(189998001)(48376002)(105586002)(106356001)(2906002)(50226002)(47776003)(8936002)(66066001); DIR:OUT; SFP:1101; SCL:1; SRVR:HE1PR05MB3210; H:localhost.localdomain; FPR:; SPF:None; PTR:InfoNoRecords; MX:1; A:1; LANG:en; Received-SPF: None (protection.outlook.com: mellanox.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; HE1PR05MB3210; 23:ZCEUABOhgvHXFsqsp7HOlq84Z2PJhCnyCpjjl1ta7?= 7kVLlWPEMajKGwbOfKhitWc+BAgUnIn3WzLbJnUU9Z5y7lb3oBqE7M/yKwpNsjWGNFIv8TRZGN4IUyLvEb9bAQxaluP109EFwWBuYJvE/Z1Fl7wCgWjZK/cBtUxfEESul7FGLPa6dsdr/6k3FNKCIQpBFVj9dXdDo6JosZ3Bpt8FF6WBtQqkHNiLRWdfG0mRmX2mSB5Gi+VStJu5VDuvkv6IfnxtdTogkR8kYe1fNUmwx8e918C9IUa4mQNCywloAZBe/zxvHsUUN4Lbeu7NU6AdLK9FG5M+AHeerJyD1T2rN2+RA9BlzbsGyJiUnQTOClXsewSrF0+o9i/ji2/iXserSLHrE1Th50IrXKIwAIyTJ5VHBuQOfJQsd0337lcIOWDHF3Bj6tXLMP/Ia/gqhWyXLjrRKQz1KsYb1fZAKXnizOxJbCi8exrzcTBNn+AV2HafjP+XCZl+QmDqikPz2mM25GrcqzEHeaWbTET7oQzKIeZhzLkalDfrqEqjAREn//TvvwhH0dSlfUOEZj4RcH1u0xFepyKHy7/7cBvdmyQ+2q/6aZufIUMfSd0ve11Z1CslejTQa8qp1S4CB/k62ZmQVBStvGmDQy79IzKXvM1R26Sumvp1mYWf9Of/eSWE7wBvFMQ/Iq8s1415kFwiKM2ACaVT5nDr95ug0VPmhhnMJpcC7ZyVWHFZAKqqDWYHhasl466BsdGGYgmMEdu35AWY5UAoHTs8iv1KRj/PnzVGf64hSjmuJl7gJUvaAB7uYRi0Ml9OSGdsswUIKk/YFqfDBO0or+jd1FSjBTGBkWOI57IzQ9Xf9V2q02T+sFuRYRQGQ0ncG3bMSyCNlkS+y0MxQIEL8RWZhHJdEVC+/GGAsrUyub5u2C3AR+OxkGOKEyheZj0TByuHiDKlcgFrtVRcUOMlTKRmUBXfdJ9ol8UXItDhzpjXfsKaFWJXVDdriwSDyZEYCT4fEBjJMC2WjGH1qmi2PwkD8kP+oGmULjWXeTyQGlhh728pzeFlFqUtWla8Rr1Ab60nZIFso2+MGIjAnQ+t/AGyYxdW77rN9Xt7w== X-Microsoft-Exchange-Diagnostics: 1; HE1PR05MB3210; 6:9lNHTwKAoRzcw/ShiGSGedY76kODJ0gzFGCKf3L/2TTq6Pf6MNtSNNC2j0gxewzJUpjBWUvLtrqcyjiehYrtLVgk5rgpXCmnYuBeytEVUNixzszp1FrFb7akKtYDSozxwz8cfWQA7k+NZYSohB8z5AGTqXr/wECCEfBDr7/Cg4uim+hj5zqCz9fqu0O3Ws2nG6ozEeP0zkCzQ3XOpdGyvYfl39Iz/zB6xHj6Rw9CnqZ4b2/XryztqPp0+9Tf0OuySqnEDwNlBXN/xCpV7Xc2FAVHaYDePKAyTjkrL8tHAKW8TBSo1LqKjzJ5FzVmc0PD2tNMH/09GD05YM/T831UpA==; 5:f25GFriBVRnU0Kdee40eXV7J7jdo39uaJFxJO6jpHHetVfIa7vcg1DGUTQPJHI0i8L+spuOkFAvLoIazr5fpDrwI1jGquBsfL14KeSpUFCdhi/TMlB7mmpyOLp3z9R6KPqmM27Sl37PuzymqxtDs2A==; 24:+iiHCOjBbvAHvuuyN+sMpRhn0Qs4kjzX4INMQVfgdLPTGIWiqPBDQO0ItjRV73y1Ixy21pcduv1DzcBtVM4lzT9kR7RpXklmK2zGHU9EXJ8=; 7:92/9d9wZNg8S0iJwL9fIDn06ejdNqQv2cjuWm2rARZhP6qy5ztv+MSvYS5Kc7fSELMQqV+vTL2EkKjUA5Sfri0GlF2IThkt+hE6pbi5w/Q5KvIbRZ3HUGUOxlj6rQ2f+KWsMq8ckOFZ4RNdz6F2rm8rIpDn4ththXhl+rDIRI0DsqGdKmT33kgarAXaQGcz8W2S32UUfDLUmZ+Jbywhu1RsNStct894Tf/58NK5jsBQ= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: Mellanox.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 19 Oct 2017 10:16:21.5338 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: a652971c-7d2e-4d9b-a6a4-d149256f461b X-MS-Exchange-Transport-CrossTenantHeadersStamped: HE1PR05MB3210 Subject: [dpdk-dev] [PATCH 2/2] doc: add flow_filtering example documentation X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Signed-off-by: Ori Kam --- doc/guides/sample_app_ug/flow_filtering.rst | 539 ++++++++++++++++++++++++++++ 1 file changed, 539 insertions(+) create mode 100644 doc/guides/sample_app_ug/flow_filtering.rst diff --git a/doc/guides/sample_app_ug/flow_filtering.rst b/doc/guides/sample_app_ug/flow_filtering.rst new file mode 100644 index 0000000..b8d59af --- /dev/null +++ b/doc/guides/sample_app_ug/flow_filtering.rst @@ -0,0 +1,539 @@ +.. 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. + + +Basic RTE Flow Filtering Sample Application +=========================================== + +The Basic RTE flow filtering sample application is a simple example of a +creating a RTE flow rule. + +It is intended as a demonstration of the basic components RTE flow rules. + + +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 + + +Running the Application +----------------------- + +To run the example in a ``linuxapp`` environment: + +.. code-block:: console + + ./build/flow -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, +``main.c`` which holds the example logic and ``flow_blocks.c`` that holds the +implementation for building the flow rule. + +The following sections provide an explanation of the main components of the +code. + +All DPDK library functions used in the sample code are prefixed with ``rte_`` +and are explained in detail in the *DPDK API Documentation*. + + +The Main Function +~~~~~~~~~~~~~~~~~ + +The ``main()`` function located in ``main.c`` file performs the initialization +and runs the main loop function. + +The first task is to initialize the Environment Abstraction Layer (EAL). The +``argc`` and ``argv`` arguments are provided to the ``rte_eal_init()`` +function. The value returned is the number of parsed arguments: + +.. code-block:: c + + int ret = rte_eal_init(argc, argv); + if (ret < 0) + rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); + + +The ``main()`` also allocates a mempool to hold the mbufs (Message Buffers) +used by the application: + +.. code-block:: c + mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", 4096, 128, 0, + RTE_MBUF_DEFAULT_BUF_SIZE, + rte_socket_id()); + +Mbufs are the packet buffer structure used by DPDK. They are explained in +detail in the "Mbuf Library" section of the *DPDK Programmer's Guide*. + +The ``main()`` function also initializes all the ports using the user defined +``init_port()`` function which is explained in the next section: + +.. code-block:: c + + init_port(); + +Once the initialization is complete, the application is ready to launch the +``main_loop()`` function. Which is explained below. + + +.. code-block:: c + + main_loop(); + +The Port Initialization Function +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The main functional part of the port initialization used in the flow filtering +application is shown below: + +.. code-block:: c + + init_port(void) + { + int ret; + uint16_t i; + struct rte_flow_error error; + 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, + }, + }; + + printf(":: initializing port: %d\n", port_id); + ret = rte_eth_dev_configure(port_id, + nr_queues, nr_queues, &port_conf); + if (ret < 0) { + rte_exit(EXIT_FAILURE, + ":: cannot configure device: err=%d, port=%u\n", + ret, port_id); + } + + /* 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); + if (ret < 0) { + rte_exit(EXIT_FAILURE, + ":: Rx queue setup failed: err=%d, port=%u\n", + ret, port_id); + } + } + + /* create flow for send packet with */ + flow = generate_ipv4_flow(port_id, selected_queue, + SRC_IP, EMPTY_MASK, + DEST_IP, FULL_MASK, &error); + if (!flow) { + printf("Flow can't be created %d message: %s\n", + error.type, + error.message ? error.message : "(no stated reason)"); + rte_exit(EXIT_FAILURE, "error in creating flow"); + } + + rte_eth_promiscuous_enable(port_id); + + ret = rte_eth_dev_start(port_id); + if (ret < 0) { + rte_exit(EXIT_FAILURE, + "rte_eth_dev_start:err=%d, port=%u\n", + ret, port_id); + } + + assert_link_status(); + + printf(":: initializing port: %d done\n", port_id); + } + +The Ethernet port is configured with default settings using the +``rte_eth_dev_configure()`` function and the ``port_conf_default`` struct: + +.. 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, + }, + }; + + ret = rte_eth_dev_configure(port_id, nr_queues, nr_queues, &port_conf); + if (ret < 0) { + rte_exit(EXIT_FAILURE, + ":: cannot configure device: err=%d, port=%u\n", + ret, port_id); + } + +For this example we are configuring number of rx 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, + mbuf_pool); + if (ret < 0) { + rte_exit(EXIT_FAILURE, + ":: Rx 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 +explanation of the ``generate_ipv4_flow()`` appears later in this document: + +.. code-block:: c + + flow = generate_ipv4_flow(port_id, selected_queue, + SRC_IP, EMPTY_MASK, + DEST_IP, FULL_MASK, &error); + +We are setting the RX port to promiscuous mode: + +.. code-block:: c + + rte_eth_promiscuous_enable(port_id); + +The last step is to start the port. + +.. code-block:: c + + ret = rte_eth_dev_start(port_id); + if (ret < 0) { + rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err%d, port=%u\n", + ret, port_id); + } + + +The main_loop function +~~~~~~~~~~~~~~~~~~~~~~ + +As we saw above the ``main()`` function calls an application function to handle +the main loop. For the flow filtering application the main_loop function +looks like the following: + +.. code-block:: c + + static void + main_loop(void) + { + struct rte_mbuf *mbufs[32]; + struct ether_hdr *eth_hdr; + uint16_t nb_rx; + uint16_t i; + uint16_t j; + + while (!force_quit) { + for (i = 0; i < nr_queues; i++) { + nb_rx = rte_eth_rx_burst(port_id, + i, mbufs, 32); + 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 *); + print_ether_addr("src=", + ð_hdr->s_addr); + print_ether_addr(" - dst=", + ð_hdr->d_addr); + printf(" - queue=0x%x", + (unsigned int)i); + printf("\n"); + rte_pktmbuf_free(m); + } + } + } + } + /* closing and releasing resources */ + rte_flow_flush(port_id, &error); + rte_eth_dev_stop(port_id); + rte_eth_dev_close(port_id); + } + +The main work of the application is reading the packets from all +queues and printing for each packet the destination queue: + +.. code-block:: c + + while (!force_quit) { + for (i = 0; i < nr_queues; i++) { + nb_rx = rte_eth_rx_burst(port_id, i, mbufs, 32); + 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 *); + print_ether_addr("src=", ð_hdr->s_addr); + print_ether_addr(" - dst=", ð_hdr->d_addr); + printf(" - queue=0x%x", (unsigned int)i); + printf("\n"); + rte_pktmbuf_free(m); + } + } + } + } + + +The forwarding loop can be interrupted and the application closed using +``Ctrl-C``. Which results in closing the port and the device using +``rte_eth_dev_stop`` and ``rte_eth_dev_close`` + +The generate_ipv4_flow function +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The generate_ipv4_rule 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, + 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 *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; + + memset(pattern, 0, sizeof(pattern)); + memset(action, 0, sizeof(action)); + + /* + * set the rule attribute. + * in this case only ingress packets will be checked. + */ + memset(&attr, 0, sizeof(struct rte_flow_attr)); + attr.ingress = 1; + + /* + * 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). + * 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). + * in this example this is the level we care about + * so we set it according to the parameters. + */ + memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4)); + memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4)); + ip_spec.hdr.dst_addr = htonl(dest_ip); + 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; + + /* the final level must be always type end */ + pattern[3].type = RTE_FLOW_ITEM_TYPE_END; + + int res = rte_flow_validate(port_id, &attr, pattern, action, error); + if(!res) + flow = rte_flow_create(port_id, &attr, pattern, action, error); + + return flow; + } + +The first part of the function is declaring the structures that will be used. + +.. code-block:: c + + struct rte_flow_attr attr; + struct rte_flow_item pattern[MAX_PATTERN_NUM]; + struct rte_flow_action action[MAX_PATTERN_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; + +The following part create the flow attributes, in our case ingress. + +.. code-block:: c + + memset(&attr, 0, sizeof(struct rte_flow_attr)); + attr.ingress = 1; + +The third part defines the action to be taken when a packet matches +the rule. In this case send the packet to queue. + +.. code-block:: c + + action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE; + 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 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: + +.. code-block:: c + + memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4)); + memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4)); + ip_spec.hdr.dst_addr = htonl(dest_ip); + 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; + +Closing the pattern part. + +.. code-block:: c + + pattern[3].type = RTE_FLOW_ITEM_TYPE_END; + +The last part of the function is to validate the rule and create it. + +.. code-block:: c + + int res = rte_flow_validate(port_id, &attr, pattern, action, &error); + if (!res) + flow = rte_flow_create(port_id, &attr, pattern, action, &error); +