From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 2AB0941E63; Tue, 9 May 2023 04:34:38 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id B2E18410D0; Tue, 9 May 2023 04:34:37 +0200 (CEST) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by mails.dpdk.org (Postfix) with ESMTP id 2F9A740EF0 for ; Tue, 9 May 2023 04:34:36 +0200 (CEST) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 348JPfuC019327; Mon, 8 May 2023 19:34:35 -0700 Received: from nam12-dm6-obe.outbound.protection.outlook.com (mail-dm6nam12lp2177.outbound.protection.outlook.com [104.47.59.177]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 3qf77v9am6-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 08 May 2023 19:34:34 -0700 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=YykGYuc5aGSCSKdufQE0ytsVeVa9aBhvTRew62lLEkM6mSlY3hNhCaTQSD57KPk98rmHC0AAK1kIux3y1eW6EEoETwNtVYm8KPO95SUykKQGptmvb6hulQ97KyM3s1nGPLDdct5qJIgS8dFgPaF8Wsa70z3+RG/JleA8ZYceaUcsTfeD0J+xWVCm3wbYJ15kxoIe9QksGeRyq/9WiPdKwoIIZugMv2SwUKwgwjrSI5BoUYg9RE1YvpGSjqQaFN3vLmRlaioVc+vq8lhOIYaD4nbCDsIr6XBbfTwUbeoLtnKc2g4KfyrL7QUOJOGHwLnFOGcN1Mmq1Zl+Wwj1MHh6iQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=vi0eYe3xa01vHMI3B0inwaP/65eTdtk2NdbfvGs8xfs=; b=GH/LWssYOFmLjCyub3J5cbdnMLziP2L5us6FVcs0Gt4x8/d8q8ZWg+0bAi222HAPp+lhWP4Og8wgVCkt9gVRy5nVThIuYuzIwfFq9Owv7uurNkFYCXWSzO2lehmSwgoLbbswj0/mjZEt9XJf6Z0iaj1/OptnntghENm22khvRWfQtSyhnEXCVA7bMAPuH4GXRo8kxQ7Tp5ywIdUe8/G8R+QUG2icd44sM8Oism4Q+IiuRD9kQjWsAIugMLM1vxX1FBrfJHq7VreqzCPNEeC6UnAcga2PYcgGSMLhh0BAJtxaUsiQOkhKd0wwR/VHiAiOvSyqb/D4aigoolcXisu6bQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=marvell.com; dmarc=pass action=none header.from=marvell.com; dkim=pass header.d=marvell.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.onmicrosoft.com; s=selector1-marvell-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=vi0eYe3xa01vHMI3B0inwaP/65eTdtk2NdbfvGs8xfs=; b=Js2rYM3iZf7nqtrrxkUwpYHPSBXGSkSm5NES/8uYrdNB4lWU4WmFMeONGp+eiTsNgE1Ospw/HckphPHK51p1p64QOKn9u4abPS6U6dCVAI2dJnHWN7T2rpyJbGhoWo72wFJOTgWyNcYyeHCcGUCc8h2/DQ98XGuOhC9EGgRqoys= Received: from CO6PR18MB3860.namprd18.prod.outlook.com (2603:10b6:5:34d::12) by DM5PR1801MB1852.namprd18.prod.outlook.com (2603:10b6:4:6c::25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6363.27; Tue, 9 May 2023 02:34:22 +0000 Received: from CO6PR18MB3860.namprd18.prod.outlook.com ([fe80::dbd:b5e0:b4b9:b7be]) by CO6PR18MB3860.namprd18.prod.outlook.com ([fe80::dbd:b5e0:b4b9:b7be%3]) with mapi id 15.20.6363.033; Tue, 9 May 2023 02:34:21 +0000 From: Sunil Kumar Kori To: Vamsi Krishna Attunuru , "dev@dpdk.org" , "thomas@monjalon.net" , Jerin Jacob Kollanukkaran CC: Vamsi Krishna Attunuru , Nithin Kumar Dabilpuram Subject: RE: [EXT] [PATCH v2 4/4] app: add testgraph application Thread-Topic: [EXT] [PATCH v2 4/4] app: add testgraph application Thread-Index: AQHZd3giERbRq4fLV0adWnhFzb7FeK9RThRQ Date: Tue, 9 May 2023 02:34:21 +0000 Message-ID: References: <20230421060245.3136217-1-vattunuru@marvell.com> <20230425131516.3308612-1-vattunuru@marvell.com> <20230425131516.3308612-5-vattunuru@marvell.com> In-Reply-To: <20230425131516.3308612-5-vattunuru@marvell.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-dg-rorf: true x-dg-ref: =?us-ascii?Q?PG1ldGE+PGF0IG5tPSJib2R5LnR4dCIgcD0iYzpcdXNlcnNcc2tvcmlcYXBw?= =?us-ascii?Q?ZGF0YVxyb2FtaW5nXDA5ZDg0OWI2LTMyZDMtNGE0MC04NWVlLTZiODRiYTI5?= =?us-ascii?Q?ZTM1Ylxtc2dzXG1zZy1mZGIwY2Y2NC1lZTExLTExZWQtYjZjNi05NGU2Zjc5?= =?us-ascii?Q?MjY4OTBcYW1lLXRlc3RcZmRiMGNmNjYtZWUxMS0xMWVkLWI2YzYtOTRlNmY3?= =?us-ascii?Q?OTI2ODkwYm9keS50eHQiIHN6PSI3MTczMCIgdD0iMTMzMjgwNzMyNTY2NjYx?= =?us-ascii?Q?MzQ0IiBoPSI4U29Kb29rU08wTUhTdDN0ZTZKMUwvakFHTDA9IiBpZD0iIiBi?= =?us-ascii?Q?bD0iMCIgYm89IjEiIGNpPSJjQUFBQUVSSFUxUlNSVUZOQ2dVQUFHWU5BQURn?= =?us-ascii?Q?S0FyQUhvTFpBYUIrUnI2c2FUMjRvSDVHdnF4cFBiZ1ZBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBSEFBQUFEMkRBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?RUFBUUVCQUFBQTNmUUFZd0NBQVFBQUFBQUFBQUFBQUo0QUFBQmhBR1FBWkFC?= =?us-ascii?Q?eUFHVUFjd0J6QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFF?= =?us-ascii?Q?QUFBQUFBQUFBQWdBQUFBQUFuZ0FBQUdNQWRRQnpBSFFBYndCdEFGOEFjQUJs?= =?us-ascii?Q?QUhJQWN3QnZBRzRBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUFBQUFBQUFBQUNBQUFB?= =?us-ascii?Q?QUFDZUFBQUFZd0IxQUhNQWRBQnZBRzBBWHdCd0FHZ0Fid0J1QUdVQWJnQjFB?= =?us-ascii?Q?RzBBWWdCbEFISUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJ?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQkFBQUFBQUFBQUFJQUFBQUFBSjRBQUFCakFIVUFj?= =?us-ascii?Q?d0IwQUc4QWJRQmZBSE1BY3dCdUFGOEFaQUJoQUhNQWFBQmZBSFlBTUFBeUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= x-dg-refone: =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUVBQUFBQUFBQUFBZ0FBQUFBQW5nQUFBR01B?= =?us-ascii?Q?ZFFCekFIUUFid0J0QUY4QWN3QnpBRzRBWHdCckFHVUFlUUIzQUc4QWNnQmtB?= =?us-ascii?Q?SE1BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFRQUFBQUFBQUFBQ0FBQUFBQUNlQUFBQVl3QjFBSE1BZEFCdkFHMEFY?= =?us-ascii?Q?d0J6QUhNQWJnQmZBRzRBYndCa0FHVUFiQUJwQUcwQWFRQjBBR1VBY2dCZkFI?= =?us-ascii?Q?WUFNQUF5QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQUFBQUFBQUFB?= =?us-ascii?Q?QUlBQUFBQUFKNEFBQUJqQUhVQWN3QjBBRzhBYlFCZkFITUFjd0J1QUY4QWN3?= =?us-ascii?Q?QndBR0VBWXdCbEFGOEFkZ0F3QURJQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBRUFBQUFBQUFBQUFnQUFBQUFBbmdBQUFH?= =?us-ascii?Q?UUFiQUJ3QUY4QWN3QnJBSGtBY0FCbEFGOEFZd0JvQUdFQWRBQmZBRzBBWlFC?= =?us-ascii?Q?ekFITUFZUUJuQUdVQVh3QjJBREFBTWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQVFBQUFBQUFBQUFDQUFBQUFBQ2VBQUFBWkFCc0FIQUFYd0J6QUd3?= =?us-ascii?Q?QVlRQmpBR3NBWHdCakFHZ0FZUUIwQUY4QWJRQmxBSE1BY3dCaEFHY0FaUUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= x-dg-reftwo: =?us-ascii?Q?QUFBQUFBQUFBQUJBQUFBQUFBQUFBSUFBQUFBQUo0QUFBQmtBR3dBY0FCZkFI?= =?us-ascii?Q?UUFaUUJoQUcwQWN3QmZBRzhBYmdCbEFHUUFjZ0JwQUhZQVpRQmZBR1lBYVFC?= =?us-ascii?Q?c0FHVUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFQUFB?= =?us-ascii?Q?QUFBQUFBQWdBQUFBQUFuZ0FBQUdVQWJRQmhBR2tBYkFCZkFHRUFaQUJrQUhJ?= =?us-ascii?Q?QVpRQnpBSE1BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUJ3QUFBQUFBQUFBQUFBQUFBUUFBQUFBQUFBQUNBQUFBQUFD?= =?us-ascii?Q?ZUFBQUFiUUJoQUhJQWRnQmxBR3dBWHdCd0FISUFid0JxQUdVQVl3QjBBRjhB?= =?us-ascii?Q?YmdCaEFHMEFaUUJ6QUY4QWNnQmxBSE1BZEFCeUFHa0FZd0IwQUdVQVpBQmZB?= =?us-ascii?Q?R0VBYkFCdkFHNEFaUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQkFBQUFBQUFBQUFJQUFBQUFBSjRBQUFCdEFHRUFjZ0Iy?= =?us-ascii?Q?QUdVQWJBQmZBSEFBY2dCdkFHb0FaUUJqQUhRQVh3QnVBR0VBYlFCbEFITUFY?= =?us-ascii?Q?d0J5QUdVQWN3QjBBSElBYVFCakFIUUFaUUJrQUY4QWFBQmxBSGdBWXdCdkFH?= =?us-ascii?Q?UUFaUUJ6QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVB?= =?us-ascii?Q?QUFBQUFBQUFBZ0FBQUFBQW5nQUFBRzBBWVFCeUFIWUFaUUJzQUd3QVh3QmhB?= =?us-ascii?Q?SElBYlFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFRQUFBQUFBQUFBQ0FBQUFB?= =?us-ascii?Q?QUNlQUFBQWJRQmhBSElBZGdCbEFHd0FiQUJmQUhBQWNnQnZBR29BWlFCakFI?= =?us-ascii?Q?UUFYd0JqQUc4QVpBQmxBSE1BQUFBQUFBQUFB?= x-dg-refthree: =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQUFBQUFBQUFBQUlB?= =?us-ascii?Q?QUFBQUFKNEFBQUJ0QUdFQWNnQjJBR1VBYkFCc0FGOEFjQUJ5QUc4QWFnQmxB?= =?us-ascii?Q?R01BZEFCZkFHTUFid0JrQUdVQWN3QmZBR1FBYVFCakFIUUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBRUFBQUFBQUFBQUFnQUFBQUFBbmdBQUFHMEFZ?= =?us-ascii?Q?UUJ5QUhZQVpRQnNBR3dBWHdCd0FISUFid0JxQUdVQVl3QjBBRjhBYmdCaEFH?= =?us-ascii?Q?MEFaUUJ6QUY4QVl3QnZBRzRBWmdCcEFHUUFaUUJ1QUhRQWFRQmhBR3dBWHdC?= =?us-ascii?Q?dEFHRUFjZ0IyQUdVQWJBQnNBRjhBWVFCdUFHUUFYd0J0QUdrQWNBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQVFBQUFBQUFBQUFDQUFBQUFBQ2VBQUFBYlFCaEFISUFkZ0JsQUd3QWJB?= =?us-ascii?Q?QmZBSEFBY2dCdkFHb0FaUUJqQUhRQVh3QnVBR0VBYlFCbEFITUFYd0J5QUdV?= =?us-ascii?Q?QWN3QjBBSElBYVFCakFIUUFaUUJrQUY4QWJRQmhBSElBZGdCbEFHd0FiQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJBQUFBQUFBQUFB?= =?us-ascii?Q?SUFBQUFBQUo0QUFBQnRBR0VBY2dCMkFHVUFiQUJzQUY4QWNBQnlBRzhBYWdC?= =?us-ascii?Q?bEFHTUFkQUJmQUc0QVlRQnRBR1VBY3dCZkFISUFaUUJ6QUhRQWNnQnBBR01B?= =?us-ascii?Q?ZEFCbEFHUUFYd0J0QUdFQWNnQjJBR1VBYkFCc0FGOEFid0J5QUY4QVlRQnlB?= =?us-ascii?Q?RzBBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFFQUFBQUFBQUFBQWdBQUFBQUFuZ0FBQUcw?= =?us-ascii?Q?QVlRQnlBSFlBWlFCc0FHd0FYd0IwQUdVQWNnQnRBR2tBYmdCMUFITUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= x-dg-reffour: QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUFBQUFBQUFBQUNBQUFBQUFDZUFBQUFiUUJoQUhJQWRnQmxBR3dBYkFCZkFIY0Fid0J5QUdRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFKQUFBQUFBQUFBQUFBQUFBQkFBQUFBQUFBQUFJQUFBQUFBQT09Ii8+PC9tZXRhPg== x-ms-publictraffictype: Email x-ms-traffictypediagnostic: CO6PR18MB3860:EE_|DM5PR1801MB1852:EE_ x-ms-office365-filtering-correlation-id: aa2fe604-d002-4fe9-cd70-08db5035e58d x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: IwQ0YSIXYlQYKAa5EpVv95IzQNQiu8BM22Uvhs4VpV4og1QMviODwqDO5W/2lR+wRtTNpIhar1uFA6sCN3JjmxP4M3ZgzrvyMQDtExNWfChw2EdUJf1RKX/OG3b+1pVqwq4ElhEnJr1anM6XKm6WrkwTr04aMBL5AH6ETirMGubLpRYwvplykMfqU02jcMaQ1vUa5LongFJn+3sXNlndkea0rFB4p441KpuGvTLNoMesToiohaxlxaYKKxND/TjOiq7LN4tx0lL5Tda7S9kfwTIql8o3OoKU7N2rBEVwgFqPi2kHvsZHwE1rWduRJSFuZanoL777ut11J+YT/A77kl8jTF8IT9NcFvnm+gr6jvOVORNWc6kxVYgvHWOVRAa9zGi1Ric30hM5E6DIJIbRBbE1hlGGsPEKXH19cR1JH5R49W1Dko84+NpJHg2lhvDf3fRPxMxT1m26OsNXhFJECsSDQ1Q/5Q2Boj4VUcHpITmNDe4qXgTBnW0wpfBnBg9xp3ljBUnQPOPaqspY2pu6ZhjVd4CDVGlBsTPhYD2LVgn6WNoZl3NCofusZPHdBWWB57XDZUA4lzgNbnvRgTJnYFh4Bw0DvzAvD0IHEJPlvffS6B5Nd0lhRa5BU+kXOei5 x-forefront-antispam-report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:CO6PR18MB3860.namprd18.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230028)(4636009)(346002)(366004)(136003)(376002)(396003)(39860400002)(451199021)(41300700001)(66476007)(38100700002)(7696005)(122000001)(38070700005)(6506007)(186003)(26005)(9686003)(107886003)(53546011)(478600001)(71200400001)(83380400001)(55016003)(66946007)(64756008)(66556008)(33656002)(76116006)(66446008)(5660300002)(4326008)(316002)(2906002)(6636002)(30864003)(52536014)(110136005)(86362001)(54906003)(8676002)(8936002)(559001)(579004); DIR:OUT; SFP:1101; x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?us-ascii?Q?+Bo7BVAivmT41ByaZcTrTNjubp3l4LYskBkpZg1in4GwzqwkCBxYj4Q+I2GM?= =?us-ascii?Q?4UrKDWf/bXtpzgANjaijRm2qEYYjgpRHoxfWGNbLTnz6Fp9s+jmI/Oiq+c9H?= =?us-ascii?Q?ver5mJxgmts0rvCAcZ8kmyjcNo1i8VoG8Sb6FofklaDUJZG12IhuTAo/QJNC?= =?us-ascii?Q?RJXG/DSnd+MnGcG1ZyzsRK3Ahd5MRemUF73CqIdeN4D+w2RbsU/F+tDn1o03?= =?us-ascii?Q?GIRtrQVZ2lz71gluWP4r7F6FrXXjEz8/LjAURq1sOMimmNFxIZkAdz5JHbgu?= =?us-ascii?Q?8N7p4Ns2NLWG+Pq+RgKwjZmUSIlKgaZ5dlfiDUrWu1LY1yjTj9p8ffYEuMoR?= =?us-ascii?Q?Obr25JJgKz0ktFHqzcM3FFZlSH3veXdgOmVKlbO0W8LcbMqW7uUMYHu3eqOo?= =?us-ascii?Q?2t2ACxpTj7GVdyR2NUzcSpUxCdy97pgjQh9ldp4Js9Jgs6BOI0I/beVsiUMb?= =?us-ascii?Q?7sqkFy3EoikTM/dKH4VVZ818jaHVr10glGP96s2OsBn5vfF6dXFu7js4EuW4?= =?us-ascii?Q?YDcnamNIY7YqDg/rkQnxSKI7CuImZr3DLykwUynURkBaMX1OBO/ayMlrCqd1?= =?us-ascii?Q?aoNLN7e2nA8VFuWMWCyoGr9LEA0Zdqs7ziCjzz8kjUzZG4Po2ipYzDGT92dP?= =?us-ascii?Q?F27amMzOT44eVH3RCBv680nZ7xwbEzL5pBq7r+nYwbWlTrpNZkXHuBmf93mG?= =?us-ascii?Q?Jb0BLsrigqnxZOKZTNKg0LR8BjfzSbNYECmh01EEBZGz3ZSXxF7ie+wSMxNe?= =?us-ascii?Q?cfjnAtYcr4Vp4e6YLj09qDSa3aaLHLp6FhABEoOnIkICpQK2ZVv1VhvBHulY?= =?us-ascii?Q?4v9MT/oY5lKwJ9E1lCALOJKoNZPyb71R3Max1rAfpFlL5KlkUWDyM8/9dvD1?= =?us-ascii?Q?VgZmrcSqeQodU8fvvTjadIqFj30Clp8w/14DR5P7D1bKT39vN1CUofZ/IOd5?= =?us-ascii?Q?4gVUmDvCR+1Ljl4LQcx3IMAtH0iuHZQChBJ/nUL8pKmk1BAQCqPOBddKbpxy?= =?us-ascii?Q?KH1yNyR0iP3Pvi5D4ehfRFI1s2gJAKJ1Z6thq2W+PYdnB0ARP3P1Xm3j9nXv?= =?us-ascii?Q?i+I12LNEu5fM3QUy1+BWqusYReqtdhoi18j8QOg/ZuinTUKShUkFh0eWqlUF?= =?us-ascii?Q?6ZMq2rvDnI/RkErZW4l7jshnPa4b/uL91/ucviza6/FY2iBCUq/tlm9Joe4Q?= =?us-ascii?Q?8V8IAxaC8bS6L9oXf19EookCXVaTvO5LzngOrFNQOtgNWlAeqjfkO9ABHdjs?= =?us-ascii?Q?SyXT41iiQZlrtEtBM1wG6lzfbVPJ1cCrNlLB+EycobwSOL5pJgX7BwutHy3+?= =?us-ascii?Q?RDU6kjJLuD+QxavcILRv0mib/MJrZyb4PHEXINiQmoB6O2At+EUOFbaE0qkr?= =?us-ascii?Q?HB5ay9jdhtNr2UaYN6U5YGtYsmHfWlVLLCX8jn1hn+yHulTfqb3cPWiH2H+a?= =?us-ascii?Q?qyPPEH/IWcHsa2ZiwPC3Is86P+q40X4o86NG9zCFpnBDKi1fyLclBPEF803z?= =?us-ascii?Q?9HI967Cfz/ZVdtR9UwZHcB6HQZeuBiH4Q1AKlCEMLBg0uda64SAVRUqMvMKj?= =?us-ascii?Q?4SK1mmsZrUpXZ1bqmnc=3D?= Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-OriginatorOrg: marvell.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: CO6PR18MB3860.namprd18.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: aa2fe604-d002-4fe9-cd70-08db5035e58d X-MS-Exchange-CrossTenant-originalarrivaltime: 09 May 2023 02:34:21.7728 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 70e1fb47-1155-421d-87fc-2e58f638b6e0 X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: kGC6qCC0uhqUf86mdpyvEy+orA58iAiImnIdNo3O7unFiBHIi9xdLfXUM0uZYg6BeDsIGae4XxLakMUL5oqKwg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM5PR1801MB1852 X-Proofpoint-ORIG-GUID: zAZDOhoPb7Z_vl0sv7_j1E7JMWIXoiyw X-Proofpoint-GUID: zAZDOhoPb7Z_vl0sv7_j1E7JMWIXoiyw X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.254,Aquarius:18.0.942,Hydra:6.0.573,FMLib:17.11.170.22 definitions=2023-05-08_18,2023-05-05_01,2023-02-09_01 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Is there any user guide similar to testpmd ? > -----Original Message----- > From: Vamsi Attunuru > Sent: Tuesday, April 25, 2023 6:45 PM > To: dev@dpdk.org; thomas@monjalon.net; Jerin Jacob Kollanukkaran > > Cc: Vamsi Krishna Attunuru ; Nithin Kumar > Dabilpuram > Subject: [EXT] [PATCH v2 4/4] app: add testgraph application >=20 > External Email >=20 > ---------------------------------------------------------------------- > Patch adds test-graph application to validate graph > and node libraries. >=20 > Signed-off-by: Vamsi Attunuru > --- > app/meson.build | 1 + > app/test-graph/cmdline.c | 211 +++++ > app/test-graph/cmdline_graph.c | 294 +++++++ > app/test-graph/cmdline_graph.h | 19 + > app/test-graph/meson.build | 14 + > app/test-graph/parameters.c | 157 ++++ > app/test-graph/testgraph.c | 1426 ++++++++++++++++++++++++++++++++ > app/test-graph/testgraph.h | 91 ++ > doc/guides/tools/index.rst | 1 + > doc/guides/tools/testgraph.rst | 131 +++ > 10 files changed, 2345 insertions(+) >=20 > diff --git a/app/meson.build b/app/meson.build > index 74d2420f67..6c7b24e604 100644 > --- a/app/meson.build > +++ b/app/meson.build > @@ -22,6 +22,7 @@ apps =3D [ > 'test-eventdev', > 'test-fib', > 'test-flow-perf', > + 'test-graph', > 'test-gpudev', > 'test-mldev', > 'test-pipeline', > diff --git a/app/test-graph/cmdline.c b/app/test-graph/cmdline.c > new file mode 100644 > index 0000000000..d9474d827a > --- /dev/null > +++ b/app/test-graph/cmdline.c > @@ -0,0 +1,211 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(C) 2023 Marvell International Ltd. > + */ Please check copyright. I think it should be " Copyright(C) 2023 Marvell."= Only. > + > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "cmdline_graph.h" > +#include "testgraph.h" > + > +static struct cmdline *testgraph_cl; > +static cmdline_parse_ctx_t *main_ctx; > + > +/* *** Help command with introduction. *** */ > +struct cmd_help_brief_result { > + cmdline_fixed_string_t help; > +}; > + > +static void > +cmd_help_brief_parsed(__rte_unused void *parsed_result, struct cmdline > *cl, __rte_unused void *data) > +{ > + cmdline_printf(cl, > + "\n" > + "Help is available for the following sections:\n\n" > + " help control : Start and stop graph wal= k.\n" > + " help display : Displaying port, stats a= nd > config " > + "information.\n" > + " help config : Configuration informatio= n.\n" > + " help all : All of the above section= s.\n\n"); > +} > + > +static cmdline_parse_token_string_t cmd_help_brief_help =3D > + TOKEN_STRING_INITIALIZER(struct cmd_help_brief_result, help, > "help"); > + > +static cmdline_parse_inst_t cmd_help_brief =3D { > + .f =3D cmd_help_brief_parsed, > + .data =3D NULL, > + .help_str =3D "help: Show help", > + .tokens =3D { > + (void *)&cmd_help_brief_help, > + NULL, > + }, > +}; > + > +/* *** Help command with help sections. *** */ > +struct cmd_help_long_result { > + cmdline_fixed_string_t help; > + cmdline_fixed_string_t section; > +}; > + > +static void > +cmd_help_long_parsed(void *parsed_result, struct cmdline *cl, > __rte_unused void *data) > +{ > + int show_all =3D 0; > + struct cmd_help_long_result *res =3D parsed_result; > + > + if (!strcmp(res->section, "all")) > + show_all =3D 1; > + > + if (show_all || !strcmp(res->section, "control")) { > + > + cmdline_printf(cl, "\n" > + "Control forwarding:\n" > + "-------------------\n\n" > + > + "start graph_walk\n" > + " Start graph_walk on worker threads.\n\n" > + > + "stop graph_walk\n" > + " Stop worker threads from running > graph_walk.\n\n" > + > + "quit\n" > + " Quit to prompt.\n\n"); > + } > + > + if (show_all || !strcmp(res->section, "display")) { > + > + cmdline_printf(cl, > + "\n" > + "Display:\n" > + "--------\n\n" > + > + "show node_list\n" > + " Display the list of supported nodes.\n\n" > + > + "show graph_stats\n" > + " Display the node statistics of graph > cluster.\n\n"); > + } > + > + if (show_all || !strcmp(res->section, "config")) { > + cmdline_printf(cl, "\n" > + "Configuration:\n" > + "--------------\n" > + "set lcore_config > (port_id0,rxq0,lcore_idX),..." > + ".....,(port_idX,rxqX,lcoreidY)\n" > + " Set lcore configuration.\n\n" > + > + "create_graph > (node0_name,node1_name,...,nodeX_name)\n" > + " Create graph instances using the provided > node details.\n\n" > + > + "destroy_graph\n" > + " Destroy the graph instances.\n\n"); > + } > +} > + > +static cmdline_parse_token_string_t cmd_help_long_help =3D > + TOKEN_STRING_INITIALIZER(struct cmd_help_long_result, help, > "help"); > + > +static cmdline_parse_token_string_t cmd_help_long_section =3D > TOKEN_STRING_INITIALIZER( > + struct cmd_help_long_result, section, "all#control#display#config"); > + > +static cmdline_parse_inst_t cmd_help_long =3D { > + .f =3D cmd_help_long_parsed, > + .data =3D NULL, > + .help_str =3D "help all|control|display|config: " > + "Show help", > + .tokens =3D { > + (void *)&cmd_help_long_help, > + (void *)&cmd_help_long_section, > + NULL, > + }, > +}; > + > +/* *** QUIT *** */ > +struct cmd_quit_result { > + cmdline_fixed_string_t quit; > +}; > + > +static void > +cmd_quit_parsed(__rte_unused void *parsed_result, struct cmdline *cl, > __rte_unused void *data) > +{ > + cmdline_quit(cl); > +} > + > +static cmdline_parse_token_string_t cmd_quit_quit =3D > + TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit"); > + > +static cmdline_parse_inst_t cmd_quit =3D { > + .f =3D cmd_quit_parsed, > + .data =3D NULL, > + .help_str =3D "quit: Exit application", > + .tokens =3D { > + (void *)&cmd_quit_quit, > + NULL, > + }, > +}; > + > +/* list of instructions */ > +static cmdline_parse_ctx_t builtin_ctx[] =3D { > + (cmdline_parse_inst_t *)&cmd_help_brief, > + (cmdline_parse_inst_t *)&cmd_help_long, > + (cmdline_parse_inst_t *)&cmd_quit, > + (cmdline_parse_inst_t *)&cmd_show_node_list, > + (cmdline_parse_inst_t *)&cmd_set_lcore_config, > + (cmdline_parse_inst_t *)&cmd_create_graph, > + (cmdline_parse_inst_t *)&cmd_destroy_graph, > + (cmdline_parse_inst_t *)&cmd_start_graph_walk, > + (cmdline_parse_inst_t *)&cmd_stop_graph_walk, > + (cmdline_parse_inst_t *)&cmd_show_graph_stats, > + NULL, > +}; > + > +int > +init_cmdline(void) > +{ > + unsigned int count; > + unsigned int i; > + > + count =3D 0; > + for (i =3D 0; builtin_ctx[i] !=3D NULL; i++) > + count++; > + > + /* cmdline expects a NULL terminated array */ > + main_ctx =3D calloc(count + 1, sizeof(main_ctx[0])); > + if (main_ctx =3D=3D NULL) > + return -1; > + > + count =3D 0; > + for (i =3D 0; builtin_ctx[i] !=3D NULL; i++, count++) > + main_ctx[count] =3D builtin_ctx[i]; > + > + return 0; > +} > + > +void > +prompt_exit(void) > +{ > + cmdline_quit(testgraph_cl); > +} > + > +/* prompt function, called from main on MAIN lcore */ > +void > +prompt(void) > +{ > + testgraph_cl =3D cmdline_stdin_new(main_ctx, "testgraph> "); > + if (testgraph_cl =3D=3D NULL) { > + fprintf(stderr, "Failed to create stdin based cmdline > context\n"); > + return; > + } > + > + cmdline_interact(testgraph_cl); > + cmdline_stdin_exit(testgraph_cl); > +} > diff --git a/app/test-graph/cmdline_graph.c b/app/test- > graph/cmdline_graph.c > new file mode 100644 > index 0000000000..d66149a224 > --- /dev/null > +++ b/app/test-graph/cmdline_graph.c > @@ -0,0 +1,294 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(C) 2023 Marvell International Ltd. > + */ > + > +#include > +#include > + > +#include > +#include > +#include > + > +#include "cmdline_graph.h" > +#include "testgraph.h" > + > +/* *** Show supported node details *** */ > +struct cmd_show_node_list_result { > + cmdline_fixed_string_t show; > + cmdline_fixed_string_t node_list; > +}; > + > +static cmdline_parse_token_string_t cmd_show_node_list_show =3D > + TOKEN_STRING_INITIALIZER(struct cmd_show_node_list_result, > show, "show"); > +static cmdline_parse_token_string_t cmd_show_node_list_node_list =3D > + TOKEN_STRING_INITIALIZER(struct cmd_show_node_list_result, > node_list, "node_list"); > + > +static void > +cmd_show_node_list_parsed(__rte_unused void *parsed_result, > __rte_unused struct cmdline *cl, > + __rte_unused void *data) > +{ > + rte_node_t node_cnt =3D rte_node_max_count(); > + rte_node_t id; > + > + printf("\n**** Supported Graph Nodes ****\n"); > + for (id =3D 0; id < node_cnt; id++) > + printf("%s\n", rte_node_id_to_name(id)); > + > + printf("********************************\n"); > +} > + > +cmdline_parse_inst_t cmd_show_node_list =3D { > + .f =3D cmd_show_node_list_parsed, > + .data =3D NULL, > + .help_str =3D "show node_list", > + .tokens =3D { > + (void *)&cmd_show_node_list_show, > + (void *)&cmd_show_node_list_node_list, > + NULL, > + }, > +}; > + > +/* *** Set lcore config *** */ > +struct cmd_set_lcore_config_result { > + cmdline_fixed_string_t set; > + cmdline_fixed_string_t lcore_config; > + cmdline_multi_string_t token_string; > +}; > + > +static cmdline_parse_token_string_t cmd_set_lcore_config_set =3D > + TOKEN_STRING_INITIALIZER(struct cmd_set_lcore_config_result, set, > "set"); > +static cmdline_parse_token_string_t cmd_set_lcore_config_lcore_config = =3D > + TOKEN_STRING_INITIALIZER(struct cmd_set_lcore_config_result, > lcore_config, "lcore_config"); > +static cmdline_parse_token_string_t cmd_set_lcore_config_token_string = =3D > TOKEN_STRING_INITIALIZER( > + struct cmd_set_lcore_config_result, token_string, > TOKEN_STRING_MULTI); > + > +static void > +cmd_set_lcore_config_parsed(void *parsed_result, __rte_unused struct > cmdline *cl, > + __rte_unused void *data) > +{ > + struct cmd_set_lcore_config_result *res =3D parsed_result; > + const char *t_str =3D res->token_string; > + int ret; > + > + /* Parse string */ > + ret =3D parse_config(t_str); > + if (ret) { > + printf(" lcore_config string parse error\n"); > + return; > + } > + > + validate_config(); > +} > + > +cmdline_parse_inst_t cmd_set_lcore_config =3D { > + .f =3D cmd_set_lcore_config_parsed, > + .data =3D NULL, > + .help_str =3D "set lcore_config " > + "(port,queue,lcore),[(port,queue,lcore) ... > (port,queue,lcore)]", > + .tokens =3D { > + (void *)&cmd_set_lcore_config_set, > + (void *)&cmd_set_lcore_config_lcore_config, > + (void *)&cmd_set_lcore_config_token_string, > + NULL, > + }, > +}; > + > +/* *** Create graph *** */ > +struct cmd_create_graph_result { > + cmdline_fixed_string_t create_graph; > + cmdline_multi_string_t token_string; > +}; > + > +static cmdline_parse_token_string_t cmd_create_graph_create_graph =3D > + TOKEN_STRING_INITIALIZER(struct cmd_create_graph_result, > create_graph, "create_graph"); > +static cmdline_parse_token_string_t cmd_create_graph_token_string =3D > + TOKEN_STRING_INITIALIZER(struct cmd_create_graph_result, > token_string, TOKEN_STRING_MULTI); > + > +static void > +cmd_create_graph_parsed(void *parsed_result, __rte_unused struct > cmdline *cl, > + __rte_unused void *data) > +{ > + struct cmd_create_graph_result *res =3D parsed_result; > + const char *t_str =3D res->token_string; > + uint64_t valid_nodes =3D 0; > + int ret; > + > + ret =3D parse_node_patterns(t_str); > + if (ret) { > + printf("parse_node_patterns failed\n"); > + cleanup_node_pattern(); > + return; > + } > + > + ret =3D validate_node_names(&valid_nodes); > + if (ret) { > + printf("validate_node_names() failed\n"); > + cleanup_node_pattern(); > + return; > + } > + > + nb_conf =3D ethdev_ports_setup(); > + > + ethdev_rxq_configure(); > + ethdev_txq_configure(); > + > + ret =3D configure_graph_nodes(valid_nodes); > + if (ret) > + rte_exit(EXIT_FAILURE, "configure_graph_nodes: err=3D%d\n", > ret); > + > + ret =3D create_graph(valid_nodes); > + if (ret) > + rte_exit(EXIT_FAILURE, "create_graph: err=3D%d\n", ret); > + > + stats =3D create_graph_cluster_stats(); > + if (stats =3D=3D NULL) > + rte_exit(EXIT_FAILURE, "create_graph_cluster_stats() > failed\n"); > + > + check_all_ports_link_status(enabled_port_mask); > + start_eth_ports(); > +} > + > +cmdline_parse_inst_t cmd_create_graph =3D { > + .f =3D cmd_create_graph_parsed, > + .data =3D NULL, > + .help_str =3D "create_graph " > + "[node_name0,node_name1,node_name2 ... > node_nameX]", > + .tokens =3D { > + (void *)&cmd_create_graph_create_graph, > + (void *)&cmd_create_graph_token_string, > + NULL, > + }, > +}; > + > +/**** Destroy graph ****/ > +struct cmd_destroy_graph_result { > + cmdline_fixed_string_t destroy_graph; > +}; > + > +static cmdline_parse_token_string_t cmd_destroy_graph_destroy_graph =3D > + TOKEN_STRING_INITIALIZER(struct cmd_destroy_graph_result, > destroy_graph, "destroy_graph"); > + > +static void > +cmd_destroy_graph_parsed(__rte_unused void *parsed_result, > __rte_unused struct cmdline *cl, > + __rte_unused void *data) > +{ > + uint32_t lcore_id; > + > + run_graph_walk =3D false; > + graph_walk_quit =3D true; > + > + RTE_LCORE_FOREACH_WORKER(lcore_id) > + rte_eal_wait_lcore(lcore_id); > + > + destroy_graph(); > + stop_eth_ports(); > +} > + > +cmdline_parse_inst_t cmd_destroy_graph =3D { > + .f =3D cmd_destroy_graph_parsed, > + .data =3D NULL, > + .help_str =3D "destroy_graph", > + .tokens =3D { > + (void *)&cmd_destroy_graph_destroy_graph, > + NULL, > + }, > +}; > + > +/**** Start graph_walk ****/ > +struct cmd_start_graph_walk_result { > + cmdline_fixed_string_t start; > + cmdline_fixed_string_t graph_walk; > +}; > + > +static cmdline_parse_token_string_t cmd_start_graph_walk_start =3D > + TOKEN_STRING_INITIALIZER(struct cmd_start_graph_walk_result, > start, "start"); > +static cmdline_parse_token_string_t cmd_start_graph_walk_graph_walk =3D > + TOKEN_STRING_INITIALIZER(struct cmd_start_graph_walk_result, > graph_walk, "graph_walk"); > + > +static void > +cmd_start_graph_walk_parsed(__rte_unused void *parsed_result, > __rte_unused struct cmdline *cl, > + __rte_unused void *data) > +{ > + static bool launch_graph_walk; > + > + if (!launch_graph_walk) { > + rte_eal_mp_remote_launch(graph_main_loop, NULL, > SKIP_MAIN); > + launch_graph_walk =3D true; > + } > + > + run_graph_walk =3D true; > +} > + > +cmdline_parse_inst_t cmd_start_graph_walk =3D { > + .f =3D cmd_start_graph_walk_parsed, > + .data =3D NULL, > + .help_str =3D "start graph_walk", > + .tokens =3D { > + (void *)&cmd_start_graph_walk_start, > + (void *)&cmd_start_graph_walk_graph_walk, > + NULL, > + }, > +}; > + > +/**** Stop graph_walk ****/ > +struct cmd_stop_graph_walk_result { > + cmdline_fixed_string_t stop; > + cmdline_fixed_string_t graph_walk; > +}; > + > +static cmdline_parse_token_string_t cmd_stop_graph_walk_stop =3D > + TOKEN_STRING_INITIALIZER(struct cmd_stop_graph_walk_result, > stop, "stop"); > +static cmdline_parse_token_string_t cmd_stop_graph_walk_graph_walk =3D > + TOKEN_STRING_INITIALIZER(struct cmd_stop_graph_walk_result, > graph_walk, "graph_walk"); > + > +static void > +cmd_stop_graph_walk_parsed(__rte_unused void *parsed_result, > __rte_unused struct cmdline *cl, > + __rte_unused void *data) > +{ > + run_graph_walk =3D false; > +} > + > +cmdline_parse_inst_t cmd_stop_graph_walk =3D { > + .f =3D cmd_stop_graph_walk_parsed, > + .data =3D NULL, > + .help_str =3D "stop graph_walk", > + .tokens =3D { > + (void *)&cmd_stop_graph_walk_stop, > + (void *)&cmd_stop_graph_walk_graph_walk, > + NULL, > + }, > +}; > + > +/**** Show graph_stats ****/ > +struct cmd_show_graph_stats_result { > + cmdline_fixed_string_t show; > + cmdline_fixed_string_t graph_stats; > +}; > + > +static cmdline_parse_token_string_t cmd_show_graph_stats_show =3D > + TOKEN_STRING_INITIALIZER(struct cmd_show_graph_stats_result, > show, "show"); > +static cmdline_parse_token_string_t cmd_show_graph_stats_graph_stats =3D > + TOKEN_STRING_INITIALIZER(struct cmd_show_graph_stats_result, > graph_stats, "graph_stats"); > + > +static void > +cmd_show_graph_stats_parsed(__rte_unused void *parsed_result, > __rte_unused struct cmdline *cl, > + __rte_unused void *data) > +{ > + if (rte_graph_has_stats_feature()) { > + if (stats) > + rte_graph_cluster_stats_get(stats, 0); > + } else { > + printf(" graph stats feature not enabled in rte_config.\n"); > + } > +} > + > +cmdline_parse_inst_t cmd_show_graph_stats =3D { > + .f =3D cmd_show_graph_stats_parsed, > + .data =3D NULL, > + .help_str =3D "show graph_stats", > + .tokens =3D { > + (void *)&cmd_show_graph_stats_show, > + (void *)&cmd_show_graph_stats_graph_stats, > + NULL, > + }, > +}; > diff --git a/app/test-graph/cmdline_graph.h b/app/test- > graph/cmdline_graph.h > new file mode 100644 > index 0000000000..2846ff5425 > --- /dev/null > +++ b/app/test-graph/cmdline_graph.h > @@ -0,0 +1,19 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(C) 2023 Marvell International Ltd. > + */ > + > +#ifndef _CMDLINE_GRAPH_H_ > +#define _CMDLINE_GRAPH_H_ > + > +extern cmdline_parse_inst_t cmd_show_node_list; > +extern cmdline_parse_inst_t cmd_set_lcore_config; > + > +extern cmdline_parse_inst_t cmd_create_graph; > +extern cmdline_parse_inst_t cmd_destroy_graph; > + > +extern cmdline_parse_inst_t cmd_start_graph_walk; > +extern cmdline_parse_inst_t cmd_stop_graph_walk; > + > +extern cmdline_parse_inst_t cmd_show_graph_stats; > + > +#endif /* _CMDLINE_GRAPH_H_ */ > diff --git a/app/test-graph/meson.build b/app/test-graph/meson.build > new file mode 100644 > index 0000000000..d93802a975 > --- /dev/null > +++ b/app/test-graph/meson.build > @@ -0,0 +1,14 @@ > +# SPDX-License-Identifier: BSD-3-Clause > +# Copyright(C) 2023 Marvell International Ltd. > + > +# override default name to drop the hyphen > +name =3D 'test-graph' > +cflags +=3D '-Wno-deprecated-declarations' > +sources =3D files( > + 'cmdline.c', > + 'cmdline_graph.c', > + 'parameters.c', > + 'testgraph.c', > +) > + > +deps +=3D ['ethdev', 'cmdline', 'graph', 'node', 'eal'] > diff --git a/app/test-graph/parameters.c b/app/test-graph/parameters.c > new file mode 100644 > index 0000000000..b990ca4a1c > --- /dev/null > +++ b/app/test-graph/parameters.c > @@ -0,0 +1,157 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(C) 2023 Marvell International Ltd. > + */ > + > +#include > +#include > + > +#include "testgraph.h" > + > +static const char short_options[] =3D "p:" /* portmask */ > + "P" /* promiscuous */ > + "i" /* interactive */ > + ; > + > +#define CMD_LINE_OPT_CONFIG "config" > +#define CMD_LINE_OPT_NODE_PATTERN "node-pattern" > +#define CMD_LINE_OPT_INTERACTIVE "interactive" > +#define CMD_LINE_OPT_NO_NUMA "no-numa" > +#define CMD_LINE_OPT_PER_PORT_POOL "per-port-pool" > +enum { > + /* Long options mapped to a short option */ > + > + /* First long only option value must be >=3D 256, so that we won't > + * conflict with short options > + */ > + CMD_LINE_OPT_MIN_NUM =3D 256, > + CMD_LINE_OPT_CONFIG_NUM, > + CMD_LINE_OPT_NODE_PATTERN_NUM, > + CMD_LINE_OPT_INTERACTIVE_NUM, > + CMD_LINE_OPT_NO_NUMA_NUM, > + CMD_LINE_OPT_PARSE_PER_PORT_POOL, > +}; > + > +static const struct option lgopts[] =3D { > + {CMD_LINE_OPT_CONFIG, 1, 0, CMD_LINE_OPT_CONFIG_NUM}, > + {CMD_LINE_OPT_NODE_PATTERN, 1, 0, > CMD_LINE_OPT_NODE_PATTERN_NUM}, > + {CMD_LINE_OPT_INTERACTIVE, 0, 0, > CMD_LINE_OPT_INTERACTIVE_NUM}, > + {CMD_LINE_OPT_NO_NUMA, 0, 0, > CMD_LINE_OPT_NO_NUMA_NUM}, > + {CMD_LINE_OPT_PER_PORT_POOL, 0, 0, > CMD_LINE_OPT_PARSE_PER_PORT_POOL}, > + {NULL, 0, 0, 0}, > +}; > + > +/* Display usage */ > +static void > +print_usage(const char *prgname) > +{ > + fprintf(stderr, > + "%s [EAL options] --" > + " -p PORTMASK" > + " [-P]" > + " [-i]" > + " --config (port,queue,lcore)[,(port,queue,lcore)]" > + " --node-pattern > (node_name0,node_name1[,node_nameX)]" > + " [--no-numa]" > + " [--per-port-pool]" > + " [--interactive]" > + > + " -p PORTMASK: Hexadecimal bitmask of ports to > configure\n" > + " -P : Enable promiscuous mode\n" > + " -i : Enter interactive mode\n" > + " --config (port,queue,lcore): Rx queue configuration\n" > + " --node-pattern (node_names): node patterns to create > graph\n" > + " --no-numa: Disable numa awareness\n" > + " --per-port-pool: Use separate buffer pool per port\n" > + " --interactive: Enter interactive mode\n", > + prgname); > +} > + > +static int > +parse_portmask(const char *portmask) > +{ > + char *end =3D NULL; > + unsigned long pm; > + > + /* Parse hexadecimal string */ > + pm =3D strtoul(portmask, &end, 16); > + if ((portmask[0] =3D=3D '\0') || (end =3D=3D NULL) || (*end !=3D '\0')) > + return 0; > + > + return pm; > +} > + > +/* Parse the argument given in the command line of the application */ > +int > +parse_cmdline_args(int argc, char **argv) > +{ > + char *prgname =3D argv[0]; > + int option_index; > + char **argvopt; > + int opt, ret; > + > + argvopt =3D argv; > + > + /* Error or normal output strings. */ > + while ((opt =3D getopt_long(argc, argvopt, short_options, lgopts, > &option_index)) !=3D EOF) { > + > + switch (opt) { > + /* Portmask */ > + case 'p': > + enabled_port_mask =3D parse_portmask(optarg); > + if (enabled_port_mask =3D=3D 0) { > + fprintf(stderr, "Invalid portmask\n"); > + print_usage(prgname); > + return -1; > + } > + break; > + > + case 'P': > + promiscuous_on =3D 1; > + break; > + > + /* Long options */ > + case CMD_LINE_OPT_CONFIG_NUM: > + ret =3D parse_config(optarg); > + if (ret) { > + fprintf(stderr, "Invalid config\n"); > + print_usage(prgname); > + return -1; > + } > + break; > + case CMD_LINE_OPT_NODE_PATTERN_NUM: > + ret =3D parse_node_patterns(optarg); > + if (ret) { > + fprintf(stderr, "Invalid node_patterns\n"); > + print_usage(prgname); > + return -1; > + } > + break; > + > + case CMD_LINE_OPT_INTERACTIVE_NUM: > + case 'i': > + printf("Interactive-mode selected\n"); > + interactive =3D 1; > + break; > + > + case CMD_LINE_OPT_NO_NUMA_NUM: > + numa_on =3D 0; > + break; > + > + case CMD_LINE_OPT_PARSE_PER_PORT_POOL: > + printf("Per port buffer pool is enabled\n"); > + per_port_pool =3D 1; > + break; > + > + default: > + print_usage(prgname); > + return -1; > + } > + } > + > + if (optind >=3D 0) > + argv[optind - 1] =3D prgname; > + ret =3D optind - 1; > + optind =3D 1; /* Reset getopt lib */ > + > + return ret; > +} > diff --git a/app/test-graph/testgraph.c b/app/test-graph/testgraph.c > new file mode 100644 > index 0000000000..aff921acf2 > --- /dev/null > +++ b/app/test-graph/testgraph.c > @@ -0,0 +1,1426 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(C) 2023 Marvell International Ltd. > + */ > + > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "testgraph.h" > + > +/* Log type */ > +#define RTE_LOGTYPE_TEST_GRAPH RTE_LOGTYPE_USER1 > + > +/* > + * Configurable number of RX/TX ring descriptors > + */ > +#define RX_DESC_DEFAULT 1024 > +#define TX_DESC_DEFAULT 1024 > + > +#define MAX_TX_QUEUE_PER_PORT RTE_MAX_ETHPORTS > +#define MAX_RX_QUEUE_PER_PORT 128 > + > +#define MAX_RX_QUEUE_PER_LCORE 16 > + > +#define NB_SOCKETS 8 > + > +/* Static global variables used within this file. */ > +uint16_t nb_rxd =3D RX_DESC_DEFAULT; > +uint16_t nb_txd =3D TX_DESC_DEFAULT; > + > +static volatile bool force_quit; > +volatile bool graph_walk_quit; > +volatile bool run_graph_walk =3D true; > + > +char node_pattern[MAX_NODE_PATTERNS][RTE_NODE_NAMESIZE] =3D {0}; > +const char **node_patterns; > +uint8_t num_patterns; > + > +uint8_t interactive; /**< interactive mode is off by default */ > +int promiscuous_on; /**< Ports set in promiscuous mode off by default. *= / > +int numa_on =3D 1; /**< NUMA is enabled by default. */ > +int per_port_pool; /**< Use separate buffer pools per port, disabled by > default */ > +int testgraph_logtype; /**< Log type for testgraph logs */ > + > +struct rte_graph_cluster_stats *stats; > + > +uint32_t enabled_port_mask; /**< Mask of enabled ports */ > + > +uint32_t nb_conf; > + > +struct lcore_rx_queue { > + uint16_t port_id; > + uint8_t queue_id; > + char node_name[RTE_NODE_NAMESIZE]; > +}; > + > +/* Lcore conf */ > +struct lcore_conf { > + uint16_t n_rx_queue; > + struct lcore_rx_queue rx_queue_list[MAX_RX_QUEUE_PER_LCORE]; > + char punt_kernel_node_name[RTE_NODE_NAMESIZE]; > + char kernel_recv_node_name[RTE_NODE_NAMESIZE]; > + > + struct rte_graph *graph; > + char name[RTE_GRAPH_NAMESIZE]; > + rte_graph_t graph_id; > +} __rte_cache_aligned; > + > +static struct lcore_conf lcore_conf[RTE_MAX_LCORE]; > + > +struct lcore_params lcore_params_array[MAX_LCORE_PARAMS]; > +static struct lcore_params lcore_params_array_default[] =3D { > + {0, 0, 2}, {1, 0, 2}, {2, 0, 2}, {0, 1, 3}, {1, 1, 3}, > + {2, 1, 3}, {0, 2, 4}, {1, 2, 4}, {2, 2, 4}, > +}; > + > +struct lcore_params *lcore_params =3D lcore_params_array_default; > +uint16_t nb_lcore_params =3D RTE_DIM(lcore_params_array_default); > + > +static struct rte_eth_conf port_conf =3D { > + .rxmode =3D { > + .mq_mode =3D RTE_ETH_MQ_RX_RSS, > + }, > + .rx_adv_conf =3D { > + .rss_conf =3D { > + .rss_key =3D NULL, > + .rss_hf =3D RTE_ETH_RSS_IP, > + }, > + }, > + .txmode =3D { > + .mq_mode =3D RTE_ETH_MQ_TX_NONE, > + }, > +}; > + > +static const struct node_list test_node_list[] =3D {{{"ethdev_rx", "ethd= ev_tx"}, > 0, 2}, > + {{"ethdev_rx", > "punt_kernel"}, 0, 2}, > + {{"kernel_recv", "ethdev_tx"}, > 0, 2} }; > + > +static const struct node_list supported_nodes[] =3D {{{"ethdev_rx"}, > TEST_GRAPH_ETHDEV_RX_NODE, 1}, > + {{"ethdev_tx"}, > TEST_GRAPH_ETHDEV_TX_NODE, 1}, > + {{"punt_kernel"}, > TEST_GRAPH_PUNT_KERNEL_NODE, 1}, > + {{"kernel_recv"}, > TEST_GRAPH_KERNEL_RECV_NODE, 1}, > + {{"ip4_lookup"}, > TEST_GRAPH_IP4_LOOKUP_NODE, 1}, > + {{"ip4_rewrite"}, > TEST_GRAPH_IP4_REWRITE_NODE, 1}, > + {{"pkt_cls"}, > TEST_GRAPH_PKT_CLS_NODE, 1}, > + {{"pkt_drop"}, > TEST_GRAPH_PKT_DROP_NODE, 1}, > + {{"NULL"}, > TEST_GRAPH_NULL_NODE, 1} }; > + > +static struct rte_mempool > *pktmbuf_pool[RTE_MAX_ETHPORTS][NB_SOCKETS]; > + > +struct rte_node_ethdev_config ethdev_conf[RTE_MAX_ETHPORTS]; > + > +static int > +check_lcore_params(void) > +{ > + uint8_t queue, lcore; > + int socketid; > + uint16_t i; > + > + for (i =3D 0; i < nb_lcore_params; ++i) { > + queue =3D lcore_params[i].queue_id; > + if (queue >=3D MAX_RX_QUEUE_PER_PORT) { > + printf("Invalid queue number: %hhu\n", queue); > + return -1; > + } > + lcore =3D lcore_params[i].lcore_id; > + if (!rte_lcore_is_enabled(lcore)) { > + printf("Error: lcore %hhu is not enabled in lcore > mask\n", lcore); > + return -1; > + } > + > + if (lcore =3D=3D rte_get_main_lcore()) { > + printf("Error: lcore %u is main lcore\n", lcore); > + return -1; > + } > + socketid =3D rte_lcore_to_socket_id(lcore); > + if ((socketid !=3D 0) && (numa_on =3D=3D 0)) { > + printf("Warning: lcore %hhu is on socket %d with > numa off\n", lcore, > + socketid); > + } > + } > + > + return 0; > +} > + > +static int > +check_port_config(void) > +{ > + uint16_t portid; > + uint16_t i; > + > + for (i =3D 0; i < nb_lcore_params; ++i) { > + portid =3D lcore_params[i].port_id; > + if ((enabled_port_mask & (1 << portid)) =3D=3D 0) { > + printf("Port %u is not enabled in port mask\n", > portid); > + return -1; > + } > + if (!rte_eth_dev_is_valid_port(portid)) { > + printf("Port %u is not present on the board\n", > portid); > + return -1; > + } > + } > + > + return 0; > +} > + > +static uint8_t > +get_port_n_rx_queues(const uint16_t port) > +{ > + int queue =3D -1; > + uint16_t i; > + > + for (i =3D 0; i < nb_lcore_params; ++i) { > + if (lcore_params[i].port_id =3D=3D port) { > + if (lcore_params[i].queue_id =3D=3D queue + 1) > + queue =3D lcore_params[i].queue_id; > + else > + rte_exit(EXIT_FAILURE, "Queue ids of the port > %d must be" > + " in sequence and must start with > 0\n", > + lcore_params[i].port_id); > + } > + } > + > + return (uint8_t)(++queue); > +} > + > +static int > +init_lcore_rx_queues(void) > +{ > + uint16_t i, nb_rx_queue; > + uint8_t lcore; > + > + for (i =3D 0; i < nb_lcore_params; ++i) { > + lcore =3D lcore_params[i].lcore_id; > + nb_rx_queue =3D lcore_conf[lcore].n_rx_queue; > + if (nb_rx_queue >=3D MAX_RX_QUEUE_PER_LCORE) { > + printf("Error: too many queues (%u) for lcore: %u\n", > + (unsigned int)nb_rx_queue + 1, (unsigned > int)lcore); > + return -1; > + } > + > + lcore_conf[lcore].rx_queue_list[nb_rx_queue].port_id =3D > lcore_params[i].port_id; > + lcore_conf[lcore].rx_queue_list[nb_rx_queue].queue_id =3D > lcore_params[i].queue_id; > + lcore_conf[lcore].n_rx_queue++; > + } > + > + return 0; > +} > + > +int > +validate_config(void) > +{ > + int rc =3D -1; > + > + if (check_lcore_params() < 0) { > + printf("check_lcore_params() failed\n"); > + goto exit; > + } > + > + if (init_lcore_rx_queues() < 0) { > + printf("init_lcore_rx_queues() failed\n"); > + goto exit; > + } > + > + if (check_port_config() < 0) { > + printf("check_port_config() failed\n"); > + goto exit; > + } > + > + return 0; > + > +exit: > + return rc; > +} > + > +#define MEMPOOL_CACHE_SIZE 256 > + > +/* > + * This expression is used to calculate the number of mbufs needed > + * depending on user input, taking into account memory for rx and > + * tx hardware rings, cache per lcore and mtable per port per lcore. > + * RTE_MAX is used to ensure that NB_MBUF never goes below a minimum > + * value of 8192 > + */ > +#define NB_MBUF(nports) = \ > + RTE_MAX((nports * nb_rx_queue * nb_rxd + nports * nb_lcores * > RTE_GRAPH_BURST_SIZE + \ > + nports * nb_tx_queue * nb_txd + nb_lcores * > MEMPOOL_CACHE_SIZE), \ > + 8192u) > + > +static int > +init_mem(uint16_t portid, uint32_t nb_mbuf) > +{ > + uint32_t lcore_id; > + int socketid; > + char s[64]; > + > + for (lcore_id =3D 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { > + if (rte_lcore_is_enabled(lcore_id) =3D=3D 0) > + continue; > + > + if (numa_on) > + socketid =3D rte_lcore_to_socket_id(lcore_id); > + else > + socketid =3D 0; > + > + if (socketid >=3D NB_SOCKETS) { > + rte_exit(EXIT_FAILURE, "Socket %d of lcore %u is out > of range %d\n", > + socketid, lcore_id, NB_SOCKETS); > + } > + > + if (pktmbuf_pool[portid][socketid] =3D=3D NULL) { > + snprintf(s, sizeof(s), "mbuf_pool_%d:%d", portid, > socketid); > + /* Create a pool with priv size of a cacheline */ > + pktmbuf_pool[portid][socketid] =3D > rte_pktmbuf_pool_create( > + s, nb_mbuf, MEMPOOL_CACHE_SIZE, > RTE_CACHE_LINE_SIZE, > + RTE_MBUF_DEFAULT_BUF_SIZE, socketid); > + if (pktmbuf_pool[portid][socketid] =3D=3D NULL) > + rte_exit(EXIT_FAILURE, "Cannot init mbuf > pool on socket %d\n", > + socketid); > + else > + printf("Allocated mbuf pool on socket %d\n", > socketid); > + } > + } > + > + return 0; > +} > + > +void > +check_all_ports_link_status(uint32_t port_mask) > +{ > +#define CHECK_INTERVAL 100 /* 100ms */ > +#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ > + uint8_t count, all_ports_up, print_flag =3D 0; > + struct rte_eth_link link; > + uint16_t portid; > + int ret; > + char link_status_text[RTE_ETH_LINK_MAX_STR_LEN]; > + > + printf("\nChecking link status"); > + fflush(stdout); > + for (count =3D 0; count <=3D MAX_CHECK_TIME; count++) { > + if (force_quit) > + return; > + all_ports_up =3D 1; > + RTE_ETH_FOREACH_DEV(portid) { > + if (force_quit) > + return; > + if ((port_mask & (1 << portid)) =3D=3D 0) > + continue; > + memset(&link, 0, sizeof(link)); > + ret =3D rte_eth_link_get_nowait(portid, &link); > + if (ret < 0) { > + all_ports_up =3D 0; > + if (print_flag =3D=3D 1) > + printf("Port %u link get failed: %s\n", > portid, > + rte_strerror(-ret)); > + continue; > + } > + /* Print link status if flag set */ > + if (print_flag =3D=3D 1) { > + rte_eth_link_to_str(link_status_text, > sizeof(link_status_text), > + &link); > + printf("Port %d %s\n", portid, > link_status_text); > + continue; > + } > + /* Clear all_ports_up flag if any link down */ > + if (link.link_status =3D=3D RTE_ETH_LINK_DOWN) { > + all_ports_up =3D 0; > + break; > + } > + } > + /* After finally printing all link status, get out */ > + if (print_flag =3D=3D 1) > + break; > + > + if (all_ports_up =3D=3D 0) { > + printf("."); > + fflush(stdout); > + rte_delay_ms(CHECK_INTERVAL); > + } > + > + /* Set the print_flag if all ports up or timeout */ > + if (all_ports_up =3D=3D 1 || count =3D=3D (MAX_CHECK_TIME - 1)) { > + print_flag =3D 1; > + printf("Done\n"); > + } > + } > +} > + > +static void > +signal_handler(int signum) > +{ > + if (signum =3D=3D SIGINT || signum =3D=3D SIGTERM) { > + printf("\n\nSignal %d received, preparing to exit...\n", > signum); > + force_quit =3D true; > + } > + prompt_exit(); > +} > + > +int > +graph_main_loop(void *conf) > +{ > + struct lcore_conf *qconf; > + struct rte_graph *graph; > + uint32_t lcore_id; > + > + RTE_SET_USED(conf); > + > + lcore_id =3D rte_lcore_id(); > + qconf =3D &lcore_conf[lcore_id]; > + graph =3D qconf->graph; > + > + if (!graph) { > + RTE_LOG(INFO, TEST_GRAPH, "Lcore %u has nothing to > do\n", lcore_id); > + return 0; > + } > + > + RTE_LOG(INFO, TEST_GRAPH, "Entering main loop on lcore %u, graph > %s(%p)\n", lcore_id, > + qconf->name, graph); > + > + while (likely(!force_quit && !graph_walk_quit)) { > + if (likely(run_graph_walk)) > + rte_graph_walk(graph); > + } > + > + return 0; > +} > + > +struct rte_graph_cluster_stats * > +create_graph_cluster_stats(void) > +{ > + struct rte_graph_cluster_stats_param s_param; > + struct rte_graph_cluster_stats *stat; > + const char *pattern =3D "worker_*"; > + > + /* Prepare stats object */ > + memset(&s_param, 0, sizeof(s_param)); > + s_param.f =3D stdout; > + s_param.socket_id =3D SOCKET_ID_ANY; > + s_param.graph_patterns =3D &pattern; > + s_param.nb_graph_patterns =3D 1; > + > + stat =3D rte_graph_cluster_stats_create(&s_param); > + if (stat =3D=3D NULL) > + rte_exit(EXIT_FAILURE, "Unable to create stats object\n"); > + > + return stat; > +} > + > +static void > +print_stats(void) > +{ > + const char topLeft[] =3D {27, '[', '1', ';', '1', 'H', '\0'}; > + const char clr[] =3D {27, '[', '2', 'J', '\0'}; > + > + while (!force_quit) { > + /* Clear screen and move to top left */ > + printf("%s%s", clr, topLeft); > + rte_graph_cluster_stats_get(stats, 0); > + rte_delay_ms(1E3); > + } > + > + rte_graph_cluster_stats_destroy(stats); > +} > + > +int > +parse_config(const char *q_arg) > +{ > + enum fieldnames { FLD_PORT =3D 0, FLD_QUEUE, FLD_LCORE, > _NUM_FLD }; > + unsigned long int_fld[_NUM_FLD]; > + const char *p, *p0 =3D q_arg; > + char *str_fld[_NUM_FLD]; > + uint32_t size; > + char s[256]; > + char *end; > + int i; > + > + nb_lcore_params =3D 0; > + > + while ((p =3D strchr(p0, '(')) !=3D NULL) { > + ++p; > + p0 =3D strchr(p, ')'); > + if (p0 =3D=3D NULL) > + goto exit; > + > + size =3D p0 - p; > + if (size >=3D sizeof(s)) > + goto exit; > + > + memcpy(s, p, size); > + s[size] =3D '\0'; > + if (rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ',') !=3D > _NUM_FLD) > + goto exit; > + for (i =3D 0; i < _NUM_FLD; i++) { > + errno =3D 0; > + int_fld[i] =3D strtoul(str_fld[i], &end, 0); > + if (errno !=3D 0 || end =3D=3D str_fld[i]) > + goto exit; > + } > + > + if (nb_lcore_params >=3D MAX_LCORE_PARAMS) { > + printf("Exceeded max number of lcore params: > %hu\n", nb_lcore_params); > + goto exit; > + } > + > + if (int_fld[FLD_PORT] >=3D RTE_MAX_ETHPORTS || > int_fld[FLD_LCORE] >=3D RTE_MAX_LCORE) { > + printf("Invalid port/lcore id\n"); > + goto exit; > + } > + > + lcore_params_array[nb_lcore_params].port_id =3D > (uint8_t)int_fld[FLD_PORT]; > + lcore_params_array[nb_lcore_params].queue_id =3D > (uint8_t)int_fld[FLD_QUEUE]; > + lcore_params_array[nb_lcore_params].lcore_id =3D > (uint8_t)int_fld[FLD_LCORE]; > + ++nb_lcore_params; > + } > + lcore_params =3D lcore_params_array; > + > + return 0; > +exit: > + /* Revert to default config */ > + lcore_params =3D lcore_params_array_default; > + nb_lcore_params =3D RTE_DIM(lcore_params_array_default); > + > + return -1; > +} > + > +int > +parse_node_patterns(const char *q_arg) > +{ > + const char *p, *p0 =3D q_arg; > + int ret =3D -EINVAL; > + uint32_t size; > + > + num_patterns =3D 0; > + > + p =3D strchr(p0, '('); > + if (p !=3D NULL) { > + ++p; > + while ((p0 =3D strchr(p, ',')) !=3D NULL) { > + size =3D p0 - p; > + if (size >=3D RTE_NODE_NAMESIZE) > + goto exit; > + > + if (num_patterns >=3D MAX_NODE_PATTERNS) { > + printf("Too many nodes passed.\n"); > + goto exit; > + } > + > + memcpy(node_pattern[num_patterns++], p, size); > + p =3D p0 + 1; > + } > + > + p0 =3D strchr(p, ')'); > + if (p0 !=3D NULL) { > + size =3D p0 - p; > + if (size >=3D RTE_NODE_NAMESIZE) > + goto exit; > + > + if (num_patterns >=3D MAX_NODE_PATTERNS) { > + printf("Too many nodes passed.\n"); > + goto exit; > + } > + > + memcpy(node_pattern[num_patterns++], p, size); > + } else { > + goto exit; > + } > + } else { > + goto exit; > + } > + > + return 0; > +exit: > + return ret; > +} > + > +static void > +set_default_node_pattern(void) > +{ > + uint16_t idx; > + > + for (idx =3D 0; idx < test_node_list[0].size; idx++) > + strcpy(node_pattern[num_patterns++], > test_node_list[0].nodes[idx]); > +} > + > +int > +validate_node_names(uint64_t *valid_nodes) > +{ > + rte_node_t node_cnt =3D rte_node_max_count(); > + bool pattern_matched =3D false; > + rte_node_t id =3D 0; > + int ret =3D -EINVAL; > + uint16_t idx, i, j; > + > + for (idx =3D 0; idx < num_patterns; idx++) { > + for (id =3D 0; id < node_cnt; id++) { > + if (strncmp(node_pattern[idx], > rte_node_id_to_name(id), > + RTE_GRAPH_NAMESIZE) =3D=3D 0) > + break; > + } > + if (node_cnt =3D=3D id) { > + printf("Invalid node name passed\n"); > + return ret; > + } > + } > + > + for (i =3D 0; i < RTE_DIM(test_node_list); i++) { > + idx =3D 0; > + if (test_node_list[i].size =3D=3D num_patterns) { > + for (j =3D 0; j < num_patterns; j++) { > + if (strncmp(node_pattern[j], > test_node_list[i].nodes[j], > + RTE_GRAPH_NAMESIZE) =3D=3D 0) > + idx++; > + } > + if (idx =3D=3D num_patterns) > + pattern_matched =3D true; > + } > + } > + > + if (!pattern_matched) { > + printf("Unsupported node pattern passed\n\n"); > + printf("Test supported node patterns are:\n"); > + for (i =3D 0; i < RTE_DIM(test_node_list); i++) { > + printf("("); > + for (j =3D 0; j < (test_node_list[i].size - 1); j++) > + printf("%s,", test_node_list[i].nodes[j]); > + printf("%s", test_node_list[i].nodes[j]); > + printf(")\n"); > + } > + > + return ret; > + } > + > + for (i =3D 0; i < RTE_DIM(supported_nodes); i++) { > + for (j =3D 0; j < num_patterns; j++) { > + if (strncmp(node_pattern[j], > supported_nodes[i].nodes[0], > + RTE_GRAPH_NAMESIZE) =3D=3D 0) { > + *valid_nodes |=3D supported_nodes[i].test_id; > + break; > + } > + } > + } > + > + return 0; > +} > + > +void > +cleanup_node_pattern(void) > +{ > + while (num_patterns) { > + memset(node_pattern[num_patterns - 1], 0, > RTE_GRAPH_NAMESIZE); > + num_patterns--; > + } > +} > + > +static int > +ethdev_tx_node_configure(void) > +{ > + struct ethdev_tx_node_main *tx_node_data; > + struct rte_node_register *tx_node; > + char name[RTE_NODE_NAMESIZE]; > + uint16_t port_id; > + uint32_t id; > + > + tx_node_data =3D ethdev_tx_node_data_get(); > + tx_node =3D ethdev_tx_node_get(); > + > + RTE_ETH_FOREACH_DEV(port_id) { > + /* Skip ports that are not enabled */ > + if ((enabled_port_mask & (1 << port_id)) =3D=3D 0) { > + printf("\nSkipping disabled port %d\n", port_id); > + continue; > + } > + > + if (!rte_eth_dev_is_valid_port(port_id)) > + return -EINVAL; > + > + /* Create a per port tx node from base node */ > + snprintf(name, sizeof(name), "%u", port_id); > + id =3D rte_node_clone(tx_node->id, name); > + tx_node_data->nodes[port_id] =3D id; > + > + printf("ethdev:: Tx node %s-%s: is at %u\n", tx_node->name, > name, id); > + } > + > + return 0; > +} > + > +static int > +punt_kernel_node_configure(void) > +{ > + struct rte_node_register *punt_node; > + char name[RTE_NODE_NAMESIZE]; > + struct lcore_conf *qconf; > + uint32_t lcore_id; > + uint32_t id; > + > + punt_node =3D punt_kernel_node_get(); > + > + for (lcore_id =3D 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { > + > + if (rte_lcore_is_enabled(lcore_id) =3D=3D 0) > + continue; > + > + qconf =3D &lcore_conf[lcore_id]; > + > + /* Create a per lcore punt_kernel node from base node */ > + snprintf(name, sizeof(name), "%u", lcore_id); > + id =3D rte_node_clone(punt_node->id, name); > + strcpy(qconf->punt_kernel_node_name, > rte_node_id_to_name(id)); > + > + printf("punt_kernel node %s-%s: is at %u\n", punt_node- > >name, name, id); > + } > + > + return 0; > +} > + > +static int > +kernel_recv_node_configure(void) > +{ > + struct rte_node_register *recv_node; > + char name[RTE_NODE_NAMESIZE]; > + struct lcore_conf *qconf; > + uint32_t lcore_id; > + uint32_t id; > + > + recv_node =3D kernel_recv_node_get(); > + > + for (lcore_id =3D 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { > + > + if (rte_lcore_is_enabled(lcore_id) =3D=3D 0) > + continue; > + > + qconf =3D &lcore_conf[lcore_id]; > + > + /* Create a per lcore kernel_recv node from base node */ > + snprintf(name, sizeof(name), "%u", lcore_id); > + id =3D rte_node_clone(recv_node->id, name); > + strcpy(qconf->kernel_recv_node_name, > rte_node_id_to_name(id)); > + > + printf("kernel_recv node %s-%s: is at %u\n", recv_node- > >name, name, id); > + } > + > + return 0; > +} > + > +static int > +ethdev_rx_node_configure(struct rte_node_ethdev_config *conf, uint16_t > nb_confs) > +{ > + char name[RTE_NODE_NAMESIZE]; > + uint16_t i, j, port_id; > + uint32_t id; > + > + for (i =3D 0; i < nb_confs; i++) { > + port_id =3D conf[i].port_id; > + > + if (!rte_eth_dev_is_valid_port(port_id)) > + return -EINVAL; > + > + /* Create node for each rx port queue pair */ > + for (j =3D 0; j < conf[i].num_rx_queues; j++) { > + struct ethdev_rx_node_main *rx_node_data; > + struct rte_node_register *rx_node; > + ethdev_rx_node_elem_t *elem; > + > + rx_node_data =3D ethdev_rx_get_node_data_get(); > + rx_node =3D ethdev_rx_node_get(); > + snprintf(name, sizeof(name), "%u-%u", port_id, j); > + /* Clone a new rx node with same edges as parent */ > + id =3D rte_node_clone(rx_node->id, name); > + if (id =3D=3D RTE_NODE_ID_INVALID) > + return -EIO; > + > + /* Add it to list of ethdev rx nodes for lookup */ > + elem =3D malloc(sizeof(ethdev_rx_node_elem_t)); > + if (elem =3D=3D NULL) > + return -ENOMEM; > + memset(elem, 0, sizeof(ethdev_rx_node_elem_t)); > + elem->ctx.port_id =3D port_id; > + elem->ctx.queue_id =3D j; > + elem->nid =3D id; > + elem->next =3D rx_node_data->head; > + rx_node_data->head =3D elem; > + > + printf("ethdev:: Rx node %s-%s: is at %u\n", rx_node- > >name, name, id); > + } > + } > + > + return 0; > +} > + > +static int > +update_ethdev_rx_node_next(rte_node_t id, const char *edge_name) > +{ > + struct ethdev_rx_node_main *rx_node_data; > + ethdev_rx_node_elem_t *elem; > + char *next_nodes[16]; > + rte_edge_t count; > + uint16_t i; > + > + count =3D rte_node_edge_count(id); > + rte_node_edge_get(id, next_nodes); > + > + for (i =3D 0; i < count; i++) { > + if (fnmatch(edge_name, next_nodes[i], 0) =3D=3D 0) { > + rx_node_data =3D ethdev_rx_get_node_data_get(); > + elem =3D rx_node_data->head; > + while (elem->next !=3D rx_node_data->head) { > + if (elem->nid =3D=3D id) > + break; > + elem =3D elem->next; > + } > + > + if (elem->nid =3D=3D id) > + elem->ctx.cls_next =3D i; > + break; > + } > + } > + > + return 0; > +} > + > +static int > +link_ethdev_rx_to_tx_node(uint32_t lcore_id) > +{ > + const char * const pattern[] =3D {"ethdev_tx-*"}; > + uint16_t queue, queue_id, port_id; > + char name[RTE_NODE_NAMESIZE]; > + const char *next_node =3D name; > + struct lcore_conf *qconf; > + uint32_t rx_id; > + > + qconf =3D &lcore_conf[lcore_id]; > + > + for (queue =3D 0; queue < qconf->n_rx_queue; ++queue) { > + port_id =3D qconf->rx_queue_list[queue].port_id; > + queue_id =3D qconf->rx_queue_list[queue].queue_id; > + > + snprintf(name, sizeof(name), "ethdev_rx-%u-%u", port_id, > queue_id); > + rx_id =3D rte_node_from_name(name); > + > + /* Fill node pattern */ > + strcpy(node_pattern[num_patterns++], name); > + > + /* Prepare the actual name of the cloned node */ > + snprintf(name, sizeof(name), "ethdev_tx-%u", port_id); > + > + /* Update ethdev_rx node edges */ > + rte_node_edge_update(rx_id, RTE_EDGE_ID_INVALID, > &next_node, 1); > + > + /* Fill node pattern */ > + strcpy(node_pattern[num_patterns++], name); > + > + /* Update node_next details */ > + update_ethdev_rx_node_next(rx_id, pattern[0]); > + } > + > + return 0; > +} > + > +static int > +link_ethdev_rx_to_punt_kernel_node(uint32_t lcore_id) > +{ > + const char * const pattern[] =3D {"punt_kernel-*"}; > + uint16_t queueid, portid, queue; > + char name[RTE_NODE_NAMESIZE]; > + const char *next_node =3D name; > + struct lcore_conf *qconf; > + rte_node_t rx_id; > + > + qconf =3D &lcore_conf[lcore_id]; > + > + for (queue =3D 0; queue < qconf->n_rx_queue; ++queue) { > + > + portid =3D qconf->rx_queue_list[queue].port_id; > + queueid =3D qconf->rx_queue_list[queue].queue_id; > + > + snprintf(name, sizeof(name), "ethdev_rx-%u-%u", portid, > queueid); > + rx_id =3D rte_node_from_name(name); > + > + /* Fill node pattern */ > + strcpy(node_pattern[num_patterns++], name); > + > + next_node =3D qconf->punt_kernel_node_name; > + > + /* Fill node pattern */ > + strcpy(node_pattern[num_patterns++], next_node); > + > + /* Update ethdev_rx node edges */ > + rte_node_edge_update(rx_id, RTE_EDGE_ID_INVALID, > &next_node, 1); > + > + /* Update node_next details */ > + update_ethdev_rx_node_next(rx_id, pattern[0]); > + } > + > + return 0; > +} > + > +static int > +update_kernel_recv_node_next(rte_node_t id, const char *edge_name) > +{ > + struct kernel_recv_node_main *rx_node_data; > + kernel_recv_node_elem_t *elem; > + char *next_nodes[16]; > + rte_edge_t count; > + uint16_t i; > + > + count =3D rte_node_edge_count(id); > + rte_node_edge_get(id, next_nodes); > + > + for (i =3D 0; i < count; i++) { > + if (fnmatch(edge_name, next_nodes[i], 0) =3D=3D 0) { > + rx_node_data =3D kernel_recv_node_data_get(); > + elem =3D rx_node_data->head; > + while (elem->next !=3D rx_node_data->head) { > + if (elem->nid =3D=3D id) > + break; > + elem =3D elem->next; > + } > + > + if (elem->nid =3D=3D id) > + elem->ctx.recv_info->cls_next =3D i; > + break; > + } > + } > + > + return 0; > +} > + > +static int > +link_kernel_recv_to_ethdev_tx_node(uint32_t lcore_id) > +{ > + const char * const pattern[] =3D {"ethdev_tx-*"}; > + char name[RTE_NODE_NAMESIZE]; > + const char *next_node =3D name; > + struct lcore_conf *qconf; > + uint16_t port_id; > + rte_node_t id; > + > + qconf =3D &lcore_conf[lcore_id]; > + > + id =3D rte_node_from_name(qconf->kernel_recv_node_name); > + > + /* Fill node pattern */ > + strcpy(node_pattern[num_patterns++], qconf- > >kernel_recv_node_name); > + > + port_id =3D lcore_id; > + > + if ((enabled_port_mask & (1 << port_id)) =3D=3D 0) { > + /* Use available port_id */ > + RTE_ETH_FOREACH_DEV(port_id) { > + if ((enabled_port_mask & (1 << port_id)) !=3D 0) > + break; > + } > + } > + > + if (!rte_eth_dev_is_valid_port(port_id)) { > + printf("Port %u is not present on the board\n", port_id); > + return -1; > + } > + > + /* Prepare the actual name of the cloned node */ > + snprintf(name, sizeof(name), "ethdev_tx-%u", port_id); > + > + /* Update ethdev_rx node edges */ > + rte_node_edge_update(id, RTE_EDGE_ID_INVALID, &next_node, 1); > + > + /* Fill node pattern */ > + strcpy(node_pattern[num_patterns++], name); > + > + /* Update node_next details */ > + update_kernel_recv_node_next(id, pattern[0]); > + > + return 0; > +} > + > +uint32_t > +ethdev_ports_setup(void) > +{ > + struct rte_eth_dev_info dev_info; > + uint32_t nb_tx_queue, nb_lcores; > + uint32_t nb_ports, nb_conf =3D 0; > + uint8_t nb_rx_queue; > + uint16_t portid; > + int ret; > + > + nb_ports =3D rte_eth_dev_count_avail(); > + nb_lcores =3D rte_lcore_count(); > + > + RTE_ETH_FOREACH_DEV(portid) { > + struct rte_eth_conf local_port_conf =3D port_conf; > + > + /* Skip ports that are not enabled */ > + if ((enabled_port_mask & (1 << portid)) =3D=3D 0) { > + printf("\nSkipping disabled port %d\n", portid); > + continue; > + } > + > + /* Init port */ > + printf("Initializing port %d ... ", portid); > + fflush(stdout); > + > + nb_rx_queue =3D get_port_n_rx_queues(portid); > + nb_tx_queue =3D nb_lcores; > + if (nb_tx_queue > MAX_TX_QUEUE_PER_PORT) > + nb_tx_queue =3D MAX_TX_QUEUE_PER_PORT; > + printf("Creating queues: nb_rxq=3D%d nb_txq=3D%u...\n", > nb_rx_queue, nb_tx_queue); > + > + rte_eth_dev_info_get(portid, &dev_info); > + > + if (dev_info.tx_offload_capa & > RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE) > + local_port_conf.txmode.offloads |=3D > RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE; > + > + local_port_conf.rx_adv_conf.rss_conf.rss_hf &=3D > dev_info.flow_type_rss_offloads; > + if (local_port_conf.rx_adv_conf.rss_conf.rss_hf !=3D > + port_conf.rx_adv_conf.rss_conf.rss_hf) { > + printf("Port %u modified RSS hash function based on > hardware support," > + "requested:%#" PRIx64 " configured:%#" PRIx64 > "\n", > + portid, port_conf.rx_adv_conf.rss_conf.rss_hf, > + local_port_conf.rx_adv_conf.rss_conf.rss_hf); > + } > + > + ret =3D rte_eth_dev_configure(portid, nb_rx_queue, > nb_tx_queue, &local_port_conf); > + if (ret < 0) > + rte_exit(EXIT_FAILURE, "Cannot configure device: > err=3D%d, port=3D%d\n", ret, > + portid); > + > + ret =3D rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, > &nb_txd); > + if (ret < 0) > + rte_exit(EXIT_FAILURE, > + "Cannot adjust number of descriptors: > err=3D%d," > + "port=3D%d\n", > + ret, portid); > + > + /* Init memory */ > + if (!per_port_pool) > + ret =3D init_mem(0, NB_MBUF(nb_ports)); > + else > + ret =3D init_mem(portid, NB_MBUF(1)); > + > + if (ret < 0) > + rte_exit(EXIT_FAILURE, "init_mem() failed\n"); > + > + /* Setup ethdev node config */ > + ethdev_conf[nb_conf].port_id =3D portid; > + ethdev_conf[nb_conf].num_rx_queues =3D nb_rx_queue; > + ethdev_conf[nb_conf].num_tx_queues =3D nb_tx_queue; > + if (!per_port_pool) > + ethdev_conf[nb_conf].mp =3D pktmbuf_pool[0]; > + > + else > + ethdev_conf[nb_conf].mp =3D pktmbuf_pool[portid]; > + ethdev_conf[nb_conf].mp_count =3D NB_SOCKETS; > + > + nb_conf++; > + } > + > + return nb_conf; > +} > + > +void > +ethdev_rxq_configure(void) > +{ > + struct rte_eth_dev_info dev_info; > + uint16_t queueid, portid; > + struct lcore_conf *qconf; > + uint8_t queue, socketid; > + uint32_t lcore_id; > + int ret; > + > + for (lcore_id =3D 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { > + if (rte_lcore_is_enabled(lcore_id) =3D=3D 0) > + continue; > + qconf =3D &lcore_conf[lcore_id]; > + printf("\nInitializing rx queues on lcore %u ... ", lcore_id); > + fflush(stdout); > + > + /* Init RX queues */ > + for (queue =3D 0; queue < qconf->n_rx_queue; ++queue) { > + struct rte_eth_rxconf rxq_conf; > + > + portid =3D qconf->rx_queue_list[queue].port_id; > + queueid =3D qconf->rx_queue_list[queue].queue_id; > + > + if (numa_on) > + socketid =3D > (uint8_t)rte_lcore_to_socket_id(lcore_id); > + else > + socketid =3D 0; > + > + printf("rxq=3D%d,%d,%d ", portid, queueid, socketid); > + fflush(stdout); > + > + rte_eth_dev_info_get(portid, &dev_info); > + rxq_conf =3D dev_info.default_rxconf; > + rxq_conf.offloads =3D port_conf.rxmode.offloads; > + if (!per_port_pool) > + ret =3D rte_eth_rx_queue_setup(portid, > queueid, nb_rxd, socketid, > + &rxq_conf, > pktmbuf_pool[0][socketid]); > + else > + ret =3D rte_eth_rx_queue_setup(portid, > queueid, nb_rxd, socketid, > + &rxq_conf, > + > pktmbuf_pool[portid][socketid]); > + if (ret < 0) > + rte_exit(EXIT_FAILURE, > "rte_eth_rx_queue_setup: err=3D%d, port=3D%d\n", > + ret, portid); > + > + snprintf(qconf->rx_queue_list[queue].node_name, > RTE_NODE_NAMESIZE, > + "ethdev_rx-%u-%u", portid, queueid); > + } > + } > + printf("\n"); > +} > + > +void > +ethdev_txq_configure(void) > +{ > + struct rte_eth_dev_info dev_info; > + struct rte_eth_txconf *txconf; > + uint16_t queueid, portid; > + uint32_t lcore_id; > + uint8_t socketid; > + int ret; > + > + RTE_ETH_FOREACH_DEV(portid) { > + struct rte_eth_conf local_port_conf =3D port_conf; > + > + /* Skip ports that are not enabled */ > + if ((enabled_port_mask & (1 << portid)) =3D=3D 0) { > + printf("\nSkipping disabled port %d\n", portid); > + continue; > + } > + > + rte_eth_dev_info_get(portid, &dev_info); > + > + /* Init one TX queue per (lcore,port) pair */ > + queueid =3D 0; > + for (lcore_id =3D 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { > + if (rte_lcore_is_enabled(lcore_id) =3D=3D 0) > + continue; > + > + if (numa_on) > + socketid =3D > (uint8_t)rte_lcore_to_socket_id(lcore_id); > + else > + socketid =3D 0; > + > + printf("txq=3D%u,%d,%d ", lcore_id, queueid, socketid); > + fflush(stdout); > + > + txconf =3D &dev_info.default_txconf; > + txconf->offloads =3D local_port_conf.txmode.offloads; > + ret =3D rte_eth_tx_queue_setup(portid, queueid, > nb_txd, socketid, txconf); > + if (ret < 0) > + rte_exit(EXIT_FAILURE, > "rte_eth_tx_queue_setup: err=3D%d, port=3D%d\n", > + ret, portid); > + queueid++; > + } > + } > + printf("\n"); > +} > + > +int > +configure_graph_nodes(uint64_t valid_nodes) > +{ > + int ret =3D 0; > + > + if (valid_nodes & TEST_GRAPH_ETHDEV_RX_NODE) { > + ret =3D ethdev_rx_node_configure(ethdev_conf, nb_conf); > + if (ret) { > + printf("ethdev_rx_node_configure: err=3D%d\n", ret); > + goto exit; > + } > + } > + > + if (valid_nodes & TEST_GRAPH_ETHDEV_TX_NODE) { > + ret =3D ethdev_tx_node_configure(); > + if (ret) { > + printf("ethdev_tx_node_configure: err=3D%d\n", ret); > + goto exit; > + } > + } > + > + if (valid_nodes & TEST_GRAPH_PUNT_KERNEL_NODE) { > + ret =3D punt_kernel_node_configure(); > + if (ret) { > + printf("punt_kernel_node_configure: err=3D%d\n", > ret); > + goto exit; > + } > + } > + > + if (valid_nodes & TEST_GRAPH_KERNEL_RECV_NODE) { > + ret =3D kernel_recv_node_configure(); > + if (ret) { > + printf("kernel_recv_node_configure: err=3D%d\n", ret); > + goto exit; > + } > + } > + > +exit: > + return ret; > +} > + > +static int > +link_graph_nodes(uint64_t valid_nodes, uint32_t lcore_id) > +{ > + int ret =3D 0; > + > + num_patterns =3D 0; > + > + if (valid_nodes =3D=3D (TEST_GRAPH_ETHDEV_TX_NODE | > TEST_GRAPH_ETHDEV_RX_NODE)) { > + ret =3D link_ethdev_rx_to_tx_node(lcore_id); > + if (ret) { > + printf("link_ethdev_rx_to_tx_node: err=3D%d\n", ret); > + goto exit; > + } > + } else if (valid_nodes =3D=3D (TEST_GRAPH_ETHDEV_RX_NODE | > TEST_GRAPH_PUNT_KERNEL_NODE)) { > + link_ethdev_rx_to_punt_kernel_node(lcore_id); > + } else if (valid_nodes =3D=3D (TEST_GRAPH_ETHDEV_TX_NODE | > TEST_GRAPH_KERNEL_RECV_NODE)) { > + link_kernel_recv_to_ethdev_tx_node(lcore_id); > + } else { > + printf("Invalid node map\n"); > + ret =3D -EINVAL; > + } > + > +exit: > + return ret; > +} > + > +void > +start_eth_ports(void) > +{ > + uint16_t portid; > + int ret; > + > + RTE_ETH_FOREACH_DEV(portid) { > + if ((enabled_port_mask & (1 << portid)) =3D=3D 0) > + continue; > + > + ret =3D rte_eth_dev_start(portid); > + if (ret < 0) > + rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=3D%d, > port=3D%d\n", ret, portid); > + > + if (promiscuous_on) > + rte_eth_promiscuous_enable(portid); > + } > +} > + > +void > +stop_eth_ports(void) > +{ > + uint16_t portid; > + int ret; > + > + RTE_ETH_FOREACH_DEV(portid) { > + if ((enabled_port_mask & (1 << portid)) =3D=3D 0) > + continue; > + printf("Closing port %d...", portid); > + ret =3D rte_eth_dev_stop(portid); > + if (ret !=3D 0) > + printf("Failed to stop port %u: %s\n", portid, > rte_strerror(-ret)); > + rte_eth_dev_close(portid); > + } > +} > + > +int > +create_graph(uint64_t valid_nodes) > +{ > + struct rte_graph_param graph_conf; > + struct lcore_conf *qconf; > + uint32_t lcore_id; > + int ret; > + > + node_patterns =3D malloc(MAX_NODE_PATTERNS * > sizeof(*node_patterns)); > + if (!node_patterns) > + return -ENOMEM; > + > + memset(&graph_conf, 0, sizeof(graph_conf)); > + graph_conf.node_patterns =3D node_patterns; > + > + for (lcore_id =3D 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { > + rte_graph_t graph_id; > + rte_edge_t i; > + > + if (rte_lcore_is_enabled(lcore_id) =3D=3D 0) > + continue; > + > + qconf =3D &lcore_conf[lcore_id]; > + > + /* Skip graph creation if no source exists */ > + if (!qconf->n_rx_queue) > + continue; > + > + ret =3D link_graph_nodes(valid_nodes, lcore_id); > + if (ret) > + rte_exit(EXIT_FAILURE, "link_graph_nodes(): > failed\n"); > + > + for (i =3D 0; i < num_patterns; i++) { > + graph_conf.node_patterns[i] =3D node_pattern[i]; > + printf("%s,", graph_conf.node_patterns[i]); > + } > + printf("\n"); > + > + graph_conf.nb_node_patterns =3D num_patterns; > + > + graph_conf.socket_id =3D rte_lcore_to_socket_id(lcore_id); > + > + snprintf(qconf->name, sizeof(qconf->name), "worker_%u", > lcore_id); > + > + graph_id =3D rte_graph_create(qconf->name, &graph_conf); > + if (graph_id =3D=3D RTE_GRAPH_ID_INVALID) > + rte_exit(EXIT_FAILURE, "rte_graph_create(): graph_id > invalid for lcore%u\n", > + lcore_id); > + > + qconf->graph_id =3D graph_id; > + qconf->graph =3D rte_graph_lookup(qconf->name); > + > + if (!qconf->graph) > + rte_exit(EXIT_FAILURE, "rte_graph_lookup(): graph > %s not found\n", > + qconf->name); > + } > + > + return 0; > +} > + > +int > +destroy_graph(void) > +{ > + uint32_t lcore_id; > + rte_graph_t id; > + int ret; > + > + RTE_LCORE_FOREACH_WORKER(lcore_id) > + { > + if (lcore_conf[lcore_id].graph) { > + id =3D > rte_graph_from_name(lcore_conf[lcore_id].name); > + if (rte_graph_destroy(id)) { > + printf("graph_id %u destroy failed.\n", id); > + ret =3D -1; > + } > + } > + } > + > + if (node_patterns) > + free(node_patterns); > + > + return ret; > +} > + > +int > +main(int argc, char **argv) > +{ > + uint64_t valid_nodes; > + uint32_t lcore_id; > + int ret; > + > + graph_walk_quit =3D false; > + force_quit =3D false; > + interactive =3D 0; > + > + node_patterns =3D NULL; > + > + signal(SIGINT, signal_handler); > + signal(SIGTERM, signal_handler); > + > + testgraph_logtype =3D rte_log_register("testgraph"); > + if (testgraph_logtype < 0) > + rte_exit(EXIT_FAILURE, "Cannot register log type"); > + > + set_default_node_pattern(); > + > + rte_log_set_level(testgraph_logtype, RTE_LOG_DEBUG); > + > + ret =3D rte_eal_init(argc, argv); > + if (ret < 0) > + rte_exit(EXIT_FAILURE, "Cannot init EAL: %s\n", > rte_strerror(rte_errno)); > + argc -=3D ret; > + argv +=3D ret; > + > + if (argc > 1) { > + ret =3D parse_cmdline_args(argc, argv); > + if (ret < 0) > + rte_exit(EXIT_FAILURE, "Invalid command line > parameters\n"); > + } > + > +#ifdef RTE_LIB_CMDLINE > + if (init_cmdline() !=3D 0) > + rte_exit(EXIT_FAILURE, "Could not initialise cmdline > context.\n"); > + > + if (interactive =3D=3D 1) { > + prompt(); > + } else > +#endif > + { > + if (validate_config() < 0) > + rte_exit(EXIT_FAILURE, "Config validation failed.\n"); > + > + ret =3D validate_node_names(&valid_nodes); > + if (ret) > + rte_exit(EXIT_FAILURE, "validate_node_names: > err=3D%d\n", ret); > + > + nb_conf =3D ethdev_ports_setup(); > + > + ethdev_rxq_configure(); > + > + ethdev_txq_configure(); > + > + ret =3D configure_graph_nodes(valid_nodes); > + if (ret) > + rte_exit(EXIT_FAILURE, "configure_graph_nodes: > err=3D%d\n", ret); > + > + ret =3D create_graph(valid_nodes); > + if (ret) > + rte_exit(EXIT_FAILURE, "create_graph: err=3D%d\n", > ret); > + > + stats =3D create_graph_cluster_stats(); > + if (stats =3D=3D NULL) > + rte_exit(EXIT_FAILURE, "create_graph_cluster_stats() > failed\n"); > + > + check_all_ports_link_status(enabled_port_mask); > + > + start_eth_ports(); > + > + /* Launch per-lcore init on every worker lcore */ > + rte_eal_mp_remote_launch(graph_main_loop, NULL, > SKIP_MAIN); > + > + /* Accumulate and print stats on main until exit */ > + if (rte_graph_has_stats_feature()) > + print_stats(); > + > + /* Wait for worker cores to exit */ > + RTE_LCORE_FOREACH_WORKER(lcore_id) { > + ret =3D rte_eal_wait_lcore(lcore_id); > + if (ret < 0) > + break; > + } > + > + ret =3D destroy_graph(); > + > + stop_eth_ports(); > + } > + > + /* clean up the EAL */ > + ret =3D rte_eal_cleanup(); > + if (ret !=3D 0) > + rte_exit(EXIT_FAILURE, "EAL cleanup failed: %s\n", strerror(- > ret)); > + > + return EXIT_SUCCESS; > +} > diff --git a/app/test-graph/testgraph.h b/app/test-graph/testgraph.h > new file mode 100644 > index 0000000000..ea1f8ef4fa > --- /dev/null > +++ b/app/test-graph/testgraph.h > @@ -0,0 +1,91 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(C) 2023 Marvell International Ltd. > + */ > + > +#ifndef _TESTGRAPH_H_ > +#define _TESTGRAPH_H_ > + > +#include > + > +#include > +#include > +#include > + > +#include > +#include > + > + > +#define MAX_LCORE_PARAMS 1024 > +#define MAX_NODE_PATTERNS 128 > + > +#ifndef BIT_ULL > +#define BIT_ULL(nr) (1ULL << (nr)) > +#endif > + > +#define TEST_GRAPH_ETHDEV_RX_NODE BIT_ULL(0) > +#define TEST_GRAPH_ETHDEV_TX_NODE BIT_ULL(1) > +#define TEST_GRAPH_PUNT_KERNEL_NODE BIT_ULL(2) > +#define TEST_GRAPH_KERNEL_RECV_NODE BIT_ULL(3) > +#define TEST_GRAPH_IP4_LOOKUP_NODE BIT_ULL(4) > +#define TEST_GRAPH_IP4_REWRITE_NODE BIT_ULL(5) > +#define TEST_GRAPH_PKT_CLS_NODE BIT_ULL(6) > +#define TEST_GRAPH_PKT_DROP_NODE BIT_ULL(7) > +#define TEST_GRAPH_NULL_NODE BIT_ULL(8) > + > +static volatile bool force_quit; > + > +extern struct rte_node_ethdev_config ethdev_conf[RTE_MAX_ETHPORTS]; > +extern uint32_t enabled_port_mask; > +extern uint32_t nb_conf; > + > +extern int promiscuous_on; /**< Ports set in promiscuous mode off by > default. */ > +extern uint8_t interactive; /**< interactive mode is disabled by > default. */ > +extern uint32_t enabled_port_mask; /**< Mask of enabled ports */ > +extern int numa_on; /**< NUMA is enabled by default. */ > +extern int per_port_pool; > + > +extern volatile bool graph_walk_quit; > +extern volatile bool run_graph_walk; > +extern struct rte_graph_cluster_stats *stats; > + > +extern char node_pattern[MAX_NODE_PATTERNS][RTE_NODE_NAMESIZE]; > +extern uint8_t num_patterns; > + > +struct node_list { > + const char *nodes[MAX_NODE_PATTERNS]; > + uint64_t test_id; > + uint8_t size; > +}; > + > +struct lcore_params { > + uint16_t port_id; > + uint8_t queue_id; > + uint8_t lcore_id; > +} __rte_cache_aligned; > + > +void prompt(void); > +void prompt_exit(void); > +int init_cmdline(void); > +int validate_config(void); > +int parse_cmdline_args(int argc, char **argv); > +uint32_t ethdev_ports_setup(void); > +void ethdev_rxq_configure(void); > +void ethdev_txq_configure(void); > +void start_eth_ports(void); > +void stop_eth_ports(void); > +int create_graph(uint64_t valid_nodes); > +int destroy_graph(void); > +int graph_main_loop(void *conf); > +struct rte_graph_cluster_stats *create_graph_cluster_stats(void); > +void check_all_ports_link_status(uint32_t port_mask); > +int configure_graph_nodes(uint64_t valid_nodes); > + > +int parse_config(const char *q_arg); > +int parse_node_patterns(const char *q_arg); > +int validate_node_names(uint64_t *valid_nodes); > +void cleanup_node_pattern(void); > + > +#define TESTGRAPH_LOG(level, fmt, args...) = \ > + rte_log(RTE_LOG_##level, testgraph_logtype, "testgraph: " fmt, > ##args) > + > +#endif /* _TESTGRAPH_H_ */ > diff --git a/doc/guides/tools/index.rst b/doc/guides/tools/index.rst > index 6f84fc31ff..f18c508fa2 100644 > --- a/doc/guides/tools/index.rst > +++ b/doc/guides/tools/index.rst > @@ -20,6 +20,7 @@ DPDK Tools User Guides > cryptoperf > comp_perf > testeventdev > + testgraph > testregex > testmldev > dts > diff --git a/doc/guides/tools/testgraph.rst b/doc/guides/tools/testgraph.= rst > new file mode 100644 > index 0000000000..3c1e058724 > --- /dev/null > +++ b/doc/guides/tools/testgraph.rst > @@ -0,0 +1,131 @@ > +.. SPDX-License-Identifier: BSD-3-Clause > + Copyright(C) 2023 Marvell International Ltd. > + > +dpdk-test-graph Application > +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D > + > +The ``dpdk-test-graph`` tool is a Data Plane Development Kit (DPDK) > application that allows > +exercising various graph library features. This application has a generi= c > framework to add > +new test configurations and expand test coverage to verify the functiona= lity > of graph nodes > +and observe the graph cluster statistics. > + > +Running the Application > +----------------------- > + > +The application has a number of command line options: > + > +.. code-block:: console > + > + dpdk-test-eventdev [EAL Options] -- [application options] > + > +EAL Options > +~~~~~~~~~~~ > + > +The following are the EAL command-line options that can be used in > conjunction > +with the ``dpdk-test-graph`` application. > +See the DPDK Getting Started Guides for more information on these > options. > + > +* ``-c `` or ``-l `` > + > + Set the hexadecimal bitmask of the cores to run on. The corelist= is a > + list of cores to use. > + > +Application Options > +~~~~~~~~~~~~~~~~~~~ > + > +The following are the application command-line options: > + > +* ``-p `` > + > + Set the ethdev port mask. > + > +* ``-P`` > + > + Set the ethdev ports in promiscuous mode. > + > +* ``--config `` > + > + Set the Rxq configuration. > + (i.e. ``--config (port_id,rxq,lcore_id)[,(port_id,rxq,lcore_id)]= ``). > + > +* ``--node-pattern `` > + > + Set the node patterns to use in graph creation. > + (i.e. ``--node-pattern (node_name0,node_name1[,node_nameX])``). > + > +* ``--per-port-pool`` > + > + Use separate buffer pool per port. > + > +* ``--no-numa`` > + > + Disable numa awareness. > + > +* ``--interactive`` > + > + Switch to interactive mode. > + > +Running the Tool > +~~~~~~~~~~~~~~~~ > + > +Here is the sample command line to run simple iofwd test:: > + > + ./dpdk-test-graph -a 0002:03:00.0 -a 0002:04:00.0 -c 0xF -- -p 0= x3 -P \ > + --config "(0,0,2),(1,0,2)" --node-pattern "(ethdev_rx,ethdev_tx)" > + > +Below is a sample command line to punt rx packets to kernel:: > + > + ./dpdk-test-graph -a 0002:03:00.0 -a 0002:04:00.0 -c 0xF -- -p 0= x3 -P \ > + --config "(0,0,2),(1,0,2)" --node-pattern "(ethdev_rx,punt_kernel= )" > + > +Interactive mode > +~~~~~~~~~~~~~~~~ > + > +Tool uses ``--interactive`` command line option to enter interactive mod= e > and use cmdline options > +to setup the required node configurations, create graph and than start > graph_walk. > + > + > +testgraph> help > + > +Help is available for the following sections: > + > + help control : Start and stop graph walk. > + help display : Displaying port, stats and config = information. > + help config : Configuration information. > + help all : All of the above sections. > + > +testgraph> help all > + > +Control forwarding: > + > +start graph_walk > + Start graph_walk on worker threads. > + > +stop graph_walk > + Stop worker threads from running graph_walk. > + > +quit > + Quit to prompt. > + > + > +Display: > + > +show node_list > + Display the list of supported nodes. > + > +show graph_stats > + Display the node statistics of graph cluster. > + > + > +Configuration: > + > +set lcore_config (port_id0,rxq0,lcore_idX),........,(port_idX,rxqX,lcore= idY) > + Set lcore configuration. > + > +create_graph (node0_name,node1_name,...,nodeX_name) > + Create graph instances using the provided node details. > + > +destroy_graph > + Destroy the graph instances. > + > +testgraph> > -- > 2.25.1