From patchwork Wed Nov 1 09:42:37 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ori Kam X-Patchwork-Id: 31078 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 065311B2AF; Wed, 1 Nov 2017 10:43:08 +0100 (CET) Received: from EUR03-DB5-obe.outbound.protection.outlook.com (mail-eopbgr40040.outbound.protection.outlook.com [40.107.4.40]) by dpdk.org (Postfix) with ESMTP id 3E7481B270 for ; Wed, 1 Nov 2017 10:43:06 +0100 (CET) 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=RG1e7COyaMGRQ9YT2J0kYnW8fMn5apqXIBTNUQCs9/Q=; b=LsuYzk/sWDwHOeDf5E3xN34ZnTx8St+XhWVvwg68gP+u9HszwJXeMIOxDAJIJXWjr656bcANCbXxybnCufzyQUBhfL0Wzp9Ra3eEysth6qxQnLAW1PGY2fQm0U6P6fZC84BtQ6gPnTPfIykhK979Ot28SJienphyRNlBPwPdsO8= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=orika@mellanox.com; Received: from localhost.localdomain (82.166.227.17) by HE1PR05MB3211.eurprd05.prod.outlook.com (2603:10a6:7:36::33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.197.13; Wed, 1 Nov 2017 09:43:02 +0000 From: Ori Kam To: adrien.mazarguil@6wind.com, john.mcnamara@intel.com, thomas@monjalon.net Cc: dev@dpdk.org, orika@mellanox.com Date: Wed, 1 Nov 2017 11:42:37 +0200 Message-Id: <01c7d2e959bcf30471c81ad9ec559aede03cfac9.1509525968.git.orika@mellanox.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1508407471-6252-1-git-send-email-orika@mellanox.com> References: <1508407471-6252-1-git-send-email-orika@mellanox.com> MIME-Version: 1.0 X-Originating-IP: [82.166.227.17] X-ClientProxiedBy: AM5PR0102CA0011.eurprd01.prod.exchangelabs.com (2603:10a6:206::24) To HE1PR05MB3211.eurprd05.prod.outlook.com (2603:10a6:7:36::33) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 4cda6f6c-d846-4756-913b-08d5210cf268 X-MS-Office365-Filtering-HT: Tenant X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(22001)(48565401081)(4534020)(4602075)(2017052603199); SRVR:HE1PR05MB3211; X-Microsoft-Exchange-Diagnostics: 1; HE1PR05MB3211; 3:pMqG+INhQPVp0NyML+hdZEc0ng84No8qIGOSBIv/ZCy/UVIVITSNXaza2YUrKPay1Y61QqVYOTQ6CCQjqW1BIDJpQmdkRBjy2Cw+/x4h464cy1JpS3GrgBF3T+I+djwLAETrkOqAxGlSWaCMvB8qMg//84G282D5w2yjW6VJn8FlN5uS9FQR6RJ2p+2eKQUTrIOPpeAAE9xj7nzWFrlRiKCpzL1ayMt1WV/tIxnYkpDLQHhCiAGaiKxEkufDEPZX; 25:guTXa2Kq6RrNgb5E1Z8yRwLdutnn2V0IGZSyXx4hc2/SgRiPjwD33ZV3LWvRT4Gf5h62ujfA3NHgHfPnrnHUGcrp4ouEnReAssJaDYV2f/1Nv3H1RVMukPhVoNldtIfwwcfe2ZWRyiINtC8IEvcEb6HMk/PhFrtowcFSy7qvWqZHOj8mqa4777353+X9CoP61xom1gB4+x6OV2po/i+zIp+g6Rb6+WAQBHcsmWM1OIHl0SOZteucyVEAq4NmBlz7PD/n0fB7IphcRc9iC73YDNBAkyXzzTA/J8CITQWDCwwFgkSDx847A9fnEbuZaw23FH6I/fS+MYvM40ECFANX0g==; 31:mM7kLLUd8qj9331M2FrBAF02pBIqi0pKvUhLl5/bM3ixLZD8V3qZyfoNc1ypbA4Fn6mmvxUYRFcEY7UlcZJm+82zW7VZwrjFBMQUl0WInsSd40PA3pRCBDKHSZPh1XWx4D+gGYb72IQTTyiK/avjK5G+xgEXigXhOf7NWfUh+8g0F7hhdfA/O77gL6o20JCa9VT/hyjmuAArPw7RLGqF10Mzeujz4Gg5bWhYuPUzU8M= X-MS-TrafficTypeDiagnostic: HE1PR05MB3211: X-LD-Processed: a652971c-7d2e-4d9b-a6a4-d149256f461b,ExtAddr X-Microsoft-Exchange-Diagnostics: 1; HE1PR05MB3211; 20:VarSxPChFFm51RFV2wg67VT2m+pF/cQgUqTSjSUK7M/1bl/ipBdKHScjO9qx1jcB92n2AdKsdyUbl6X9R86N5ZDwchQEkvRP7zEUP4dC5swb5CFlZAiaUDKWZ6Z/kXv8KowuYVfaRbIduVMcjL96xwJoPgckyY1FX8n4ECF+4QwQZ4QzEub7sRJDLH3pU92wnxlrgwc51yA8wHi2vMoITrPlLVtsNBbJGPgr1nJO3XDYqR77OkMwqlbxW2Iuv6UagAbx4elrAfstE0bs7Tduw2+mDVlp4e1DPF9iUVYCZtMWnjptc/RC8CvkX9ftYKbbdOGSX4v3puyAt7zX62qLz1xoAA/0hCwqHk97MLASayPnOjfFiLP2Z1suRN53K1nacM6dWhAeO90Si8fgl9heGZ9m8UcnpG+DrdT9mgepbUxtgWoMyyXEWSeHpHZdhpBkmh6ZTVIUqdjMm+HlsQk0nhue6Z6CMelDkUVCeb8NiEcZ7RQ6tpiLB4R5LN0FDiTE X-Exchange-Antispam-Report-Test: UriScan:(158342451672863)(278428928389397)(200054503718035)(116097685857584)(211171220733660)(228905959029699); X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(6040450)(2401047)(8121501046)(5005006)(100000703101)(100105400095)(93006095)(93001095)(3231020)(3002001)(10201501046)(6055026)(6041248)(20161123560025)(20161123562025)(20161123555025)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(20161123564025)(20161123558100)(6072148)(201708071742011)(100000704101)(100105200095)(100000705101)(100105500095); SRVR:HE1PR05MB3211; BCL:0; PCL:0; RULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095); SRVR:HE1PR05MB3211; X-Microsoft-Exchange-Diagnostics: 1; HE1PR05MB3211; 4:a1qRbU01ey0gJegyr85F9R/rFemzbRwEJ80Jx5XcLgJl1NCUTNdv4E/llL74jVEYLkF8lLOnVVirOhXXrJJxQaZHthKfkEy7/HqxrPD6RgB18+PJGoehUAYAa5Cq0TrAZji7+db0spNUtdjPJ5FEEXGn0JvcQeNKE+cxKax/N8bJInl+MvKk47TsrjPiClcHBhZc9760s0YmX5w1P+H9uniwXUcBLV2WXe68T9uIEOeiS1joMOJqauu0ufxjZfRUwTTNKqYgCbSbj7KCdEra7TbJd/Eax6euxw5ACFS0tcKR914zMg02bS+nshK0YlpNlfeFaJkpuNz4syhsOTqOr5pN9PhGFlsyhvdeXvBhUjXPqffZp4WHiKIIdEFKR7epn49/X5OHWvDtaxuY1slYcnD31nyGenF6mRgi1bnvBJset6aHwFy5SIIAlvhqn5fw8QThmutzOA7wxXJWOjPXOZw02iWlsgd83/LQuElLZoI= X-Forefront-PRVS: 0478C23FE0 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(6069001)(6009001)(376002)(346002)(39860400002)(51234002)(189002)(199003)(2906002)(16586007)(5003940100001)(3846002)(6116002)(5660300001)(316002)(50986999)(86362001)(76176999)(33646002)(53946003)(107886003)(118296001)(105586002)(106356001)(53936002)(101416001)(6512007)(305945005)(2950100002)(6666003)(8676002)(66066001)(16526018)(68736007)(36756003)(48376002)(7736002)(81166006)(81156014)(25786009)(97736004)(4326008)(47776003)(50466002)(50226002)(8936002)(6506006)(189998001)(6486002)(478600001); DIR:OUT; SFP:1101; SCL:1; SRVR:HE1PR05MB3211; 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; HE1PR05MB3211; 23:vTLIItU8KvbAXECeeHboWuknZTwunZBmdom6FW8aS?= hkwL88KT+2LmlrpXeYPc+zgFuA3HNwuuESgvBZXzWrI6AWVuUVmTBdP17nKUOqSxXSRCMl+7gSEjdlLmi8fJcN2j5daWZH6k69CulAjMN7jppMGwnWf78ad7M1lR9H299puIe+2cK3vqbCgXuHPardnSmpch+qCTaNJnAg+D+3kquTWr53XJ/zwygizndwUDsxjnHQiPOOHdUHe3vp8S41gCWhMnw9yyXEBkdhbBmFW0aMiyaXSBGztJElFLCJr/dkkU/US/0SEw1+2V+CWz56DocsTkNaIQDAA47QbXoG/WW0kwuoWn9ex65vWPAXkPa7d6TJDUQw8ifJQkYR1rB47gIlVitdEreffhYi5A54/PDOXNscAHt2934mgOQQesXvc09NaX5ACRSTWib+wFv06EUsluHyDJXYycSnaIY1JTkMJikDjM7hmXXKdUTp6sBigOsOht1iaSXdRi+8BJJjaZTJWbHsJWIgxeSLqgn797r73c0/0UqKVg/MLN+nWnY97BrvikgZiUNjYcx6c4Ln874w6TF+WSPd5okPDQ8xDt0hSuOH4stR0oxq2haZjZ8mzMkpGTc/7Pta7ukyIKSbTPeFW8fx2Dcazynz49PrFheOxsV0vQ6p3ZPqFbcNYBK1BZCKKdxtwmpPzoA4iDUt6nG9/GvuGsUezbp9H8d0N1JidbJxiFZvcl9POe0+MSAa0CLw5oaMoIrGcP/7GqsLG7b0MueVIhONy8ueQFhOuONqQTpynZSMykM4k7VQ6/k71MmvGl8yBk3+Ps131aVaCfAmrrPSpjF6uu7EJTpcS9kOrgoY0/54uYJrpQ8XLFSmfIMtvFIEpOEG+tIshiaSbfovl68yhOHm4fZmNhYnLJjvMuZTfJVVQ9T71WUegR8eXup/eRLZdmlmcHUgYtNyneHADy4goaLI2bdgMsXGa2umyg0N1HKq4VMWQzarKhDkhe1+e5bGk+If4sYgFZZWCZ5aT5JRGiqHb0cvPVQPJleJbhziDpfxbInFKcNcLt3z1UPtiFBy7yyXXv9JSjKeFSN4+ZRR/Mx0orE9RqPK1d/H+nv/twZ8mWp7XMM7MCCGtkQ498sb146pdqVEqA7IOloVjGu6xJt6JrLUAHau7DpGMB/x8nhNQFRrqjBsZbh4= X-Microsoft-Exchange-Diagnostics: 1; HE1PR05MB3211; 6:zpmZA+LXjY16MDFFW34F8UN+vgUHRpViIIW6t+lZdrez6spG+feInxEcs1gv22i6qXBmqN2WsBX87ruAXCrA6FHZlz9ZOSDr7e8XgFrWk7r3AylqnntevniPHMQPlUHhpkvBwlrrgxxEIYT3/Hgn/3vjNIhX5XlUNT0xIPowoUYz0A1MSihp+5jyPO2y6OBYXGsYFU+fpn9EY++vcO51OQ4jridi99z7s79v00JOgFW9wZ8FcNqanI7fub/kxs/iFZ9Du/eHQLcIWuA6uBXGPACVMyUONqkKgyoskzATHfK9TsEZCDLqbG2wAmoEd/S3X945RlpkMNzGD1+sHZCyQszwOUb+2JelnQtPrRkxdkU=; 5:xfj263ymKsE/AJhstoRbEZxD8813nwATJJVRrv1oVLoQSjwdFGkDP7C6d3IWsY7fctxGPynT99C6Hd6cVmZtVV0tZVts9+TTo+3UxEkghjHe4l1AvoaOGEJuhAKEENuHu4uGzuEMNnqGCW64PDzaRB1dSa9uwWSC+F/h8f6zohk=; 24:mEn3u/eSxDpBEsk5TK7lT6kGeaDxxy06MMAJSJsLwdrLkF5WqfilSviI96nWMSRtRfv6tJjh9tr+NXAd6XaVkhOUXbaASPCuWWYAFCawKdY=; 7:mQh7Hc9oKGQz1nFn14ycekBe7Z+NJ7OzZapz9t/Ac8JsAKAcXoW5hYHlV4rbQy3Y5YkHj8B5QTuT7d6xXXIHKnK+BwpluAVgEArHpghufYbUyB7x1m9FAzU6v2BPngEkVOWiiZVcMCczx2TW/DODe1nnxBc62z71Fd0nzbzr68RXlrBOZ5OJh/K1heJT5BnzOmyB1BTrFcFQyy1S8Srxm1/bmuNmD1iLqkmijkvr5akw2mHuymv1I+yZf+E2ZAMN SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: Mellanox.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Nov 2017 09:43:02.4619 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 4cda6f6c-d846-4756-913b-08d5210cf268 X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: a652971c-7d2e-4d9b-a6a4-d149256f461b X-MS-Exchange-Transport-CrossTenantHeadersStamped: HE1PR05MB3211 Subject: [dpdk-dev] [PATCH v3] examples/flow_filtering: demo of simple rte flow 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" This application shows a simple usage of the rte_flow API for hardware filtering offloading. In this demo we are filtering specific IP to specific target queue, while sending all the rest of the packets to other queue. Signed-off-by: Ori Kam --- v3: * Fix the position of the example doc according to alphabetical order. * Fix the position of the example ine the Makefile to alphabetical order. * Add license header to example make file. * Fix CFLAGS typo. * Fix copyright in main.c v2: * Merge patches into one patch. * Add flow_filtering doc to index. * Add example to Makefile. * Small fixes. * Remove cover letter. MAINTAINERS | 4 + doc/guides/sample_app_ug/flow_filtering.rst | 545 ++++++++++++++++++++++++++++ doc/guides/sample_app_ug/index.rst | 1 + examples/Makefile | 1 + examples/flow_filtering/Makefile | 49 +++ examples/flow_filtering/flow_blocks.c | 150 ++++++++ examples/flow_filtering/main.c | 244 +++++++++++++ 7 files changed, 994 insertions(+) create mode 100644 doc/guides/sample_app_ug/flow_filtering.rst create mode 100644 examples/flow_filtering/Makefile create mode 100644 examples/flow_filtering/flow_blocks.c create mode 100644 examples/flow_filtering/main.c diff --git a/MAINTAINERS b/MAINTAINERS index 2a58378..976252e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -914,6 +914,10 @@ F: doc/guides/sample_app_ug/ethtool.rst F: examples/exception_path/ F: doc/guides/sample_app_ug/exception_path.rst +M: Ori Kam +F: examples/flow_filtering/ +F: doc/guides/sample_app_ug/flow_filtering.rst + M: Bruce Richardson M: Pablo de Lara F: examples/helloworld/ 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..725dcb4 --- /dev/null +++ b/doc/guides/sample_app_ug/flow_filtering.rst @@ -0,0 +1,545 @@ +.. 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, we set the flow rule using the +following code: + +.. code-block:: c + + /* 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"); + } + +In the last part 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_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); + } + } + + + 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); + diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst index 069d4f1..ca1f544 100644 --- a/doc/guides/sample_app_ug/index.rst +++ b/doc/guides/sample_app_ug/index.rst @@ -77,6 +77,7 @@ Sample Applications User Guides ptpclient performance_thread ipsec_secgw + flow_filtering **Figures** diff --git a/examples/Makefile b/examples/Makefile index d27eddd..77f84d6 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -42,6 +42,7 @@ DIRS-y += cmdline DIRS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += distributor DIRS-y += ethtool DIRS-y += exception_path +DIRS-y += flow_filtering DIRS-$(CONFIG_RTE_LIBRTE_EFD) += server_node_efd DIRS-y += helloworld DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += ip_pipeline diff --git a/examples/flow_filtering/Makefile b/examples/flow_filtering/Makefile new file mode 100644 index 0000000..70b82fe --- /dev/null +++ b/examples/flow_filtering/Makefile @@ -0,0 +1,49 @@ +# +# BSD LICENSE +# +# Copyright 2017 Mellanox. +# +# 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 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. +# + +ifeq ($(RTE_SDK),) +$(error "Please define RTE_SDK environment variable") +endif + +# Default target, can be overridden by command line or environment +RTE_TARGET ?= x86_64-native-linuxapp-gcc + +include $(RTE_SDK)/mk/rte.vars.mk + +APP = flow + +SRCS-y := main.c + +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) + +include $(RTE_SDK)/mk/rte.extapp.mk diff --git a/examples/flow_filtering/flow_blocks.c b/examples/flow_filtering/flow_blocks.c new file mode 100644 index 0000000..f92df10 --- /dev/null +++ b/examples/flow_filtering/flow_blocks.c @@ -0,0 +1,150 @@ +/*- + * BSD LICENSE + * + * Copyright 2017 Mellanox. + * + * 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 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. + */ + +#define MAX_PATTERN_NUM 4 + +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); + + +/** + * create a flow rule that sends packets with matching src and dest ip + * to selected queue. + * + * @param port_id + * The selected port. + * @param rx_q + * The selected target queue. + * @param src_ip + * The src ip value to match the input packet. + * @param src_mask + * The mask to apply to the src ip. + * @param dest_ip + * The dest ip value to match the input packet. + * @param dest_mask + * The mask to apply to the dest ip. + * @param[out] error + * Perform verbose error reporting if not NULL. + * + * @return + * A flow if the rule could be created else return NULL. + */ +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; + int res; + + 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; + + res = rte_flow_validate(port_id, &attr, pattern, action, error); + if (!res) + flow = rte_flow_create(port_id, &attr, pattern, action, error); + + return flow; +} + diff --git a/examples/flow_filtering/main.c b/examples/flow_filtering/main.c new file mode 100644 index 0000000..7d739b4 --- /dev/null +++ b/examples/flow_filtering/main.c @@ -0,0 +1,244 @@ +/*- + * BSD LICENSE + * + * Copyright 2017 Mellanox. + * + * 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. 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static volatile bool force_quit; + +static uint8_t port_id; +static uint16_t nr_queues = 5; +static uint8_t selected_queue = 1; +struct rte_mempool *mbuf_pool; +struct rte_flow *flow; + +#define SRC_IP ((0<<24) + (0<<16) + (0<<8) + 0) /* src ip = 0.0.0.0 */ +#define DEST_IP ((192<<24) + (168<<16) + (1<<8) + 1) /* dest ip = 192.168.1.1 */ +#define FULL_MASK 0xffffffff /* full mask */ +#define EMPTY_MASK 0x0 /* empty mask */ + +#include "flow_blocks.c" + +static inline void +print_ether_addr(const char *what, struct ether_addr *eth_addr) +{ + char buf[ETHER_ADDR_FMT_SIZE]; + ether_format_addr(buf, ETHER_ADDR_FMT_SIZE, eth_addr); + printf("%s%s", what, buf); +} + +static void +main_loop(void) +{ + struct rte_mbuf *mbufs[32]; + struct ether_hdr *eth_hdr; + struct rte_flow_error error; + 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); +} + +static void +assert_link_status(void) +{ + struct rte_eth_link link; + + memset(&link, 0, sizeof(link)); + rte_eth_link_get(port_id, &link); + if (link.link_status == ETH_LINK_DOWN) + rte_exit(EXIT_FAILURE, ":: error: link is still down\n"); +} + +static void +init_port(void) +{ + int ret; + uint16_t i; + 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); + } + } + + 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); +} + +static void +signal_handler(int signum) +{ + if (signum == SIGINT || signum == SIGTERM) { + printf("\n\nSignal %d received, preparing to exit...\n", + signum); + force_quit = true; + } +} + +int +main(int argc, char **argv) +{ + int ret; + uint8_t nr_ports; + struct rte_flow_error error; + + ret = rte_eal_init(argc, argv); + if (ret < 0) + rte_exit(EXIT_FAILURE, ":: invalid EAL arguments\n"); + + force_quit = false; + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + + nr_ports = rte_eth_dev_count(); + if (nr_ports == 0) + rte_exit(EXIT_FAILURE, ":: no Ethernet ports found\n"); + port_id = 0; + if (nr_ports != 1) { + printf(":: warn: %d ports detected, but we use only one: port %u\n", + nr_ports, port_id); + } + mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", 4096, 128, 0, + RTE_MBUF_DEFAULT_BUF_SIZE, + rte_socket_id()); + if (mbuf_pool == NULL) + rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n"); + + init_port(); + + /* 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"); + } + + main_loop(); + + return 0; +}