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 40F0A4254E; Sat, 9 Sep 2023 03:18:17 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id CCA14402B1; Sat, 9 Sep 2023 03:18:16 +0200 (CEST) Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) by mails.dpdk.org (Postfix) with ESMTP id D969C4027F for ; Sat, 9 Sep 2023 03:18:14 +0200 (CEST) Received: from pps.filterd (m0045851.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 388IF1GD020877; Fri, 8 Sep 2023 18:18:14 -0700 Received: from nam12-mw2-obe.outbound.protection.outlook.com (mail-mw2nam12lp2046.outbound.protection.outlook.com [104.47.66.46]) by mx0b-0016f401.pphosted.com (PPS) with ESMTPS id 3t08qrs4ac-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 08 Sep 2023 18:18:13 -0700 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=dfpOJMB2/enILPtoJPg+keQ4Cxzy4Iy+h1sQqi/4pjRousJCMLDFvB5FhVzWgnQbNago24eXeUKPfRhcu2IsWe/wJZ/Pd5J1HaJuGW7Ix2sHpGiSAGCmsqrwWSD9v9jhBNg62I5gYbn3hWewTq7F2m/XKjsO90dCNz5g+iZmLgcglDJcZNFA+gn25mdp2EgsjRHCc4PsxbZ7nVmy5V58KUFI/RWWTOlbDiRLx4iZ3ZoIfy4ExeRxx49xVvj8ql5J2cDw1Jox+2cJpLC5pnEmw/XpWprhgVkYRl3KmTHGGyen3HjMMBP3VsLUxdD4YBYZcpXBmjgZ2RWWm/CwlHqOJQ== 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=hACV4dnFSXiWJ/ry9NLN404p8Pa80Ae2lDVLVikhDvk=; b=OulCayukokz4O82P7lv1J29UqAKL4wUehN3N8ZrWL5kgM+NJtMpKfhYUPS62nk9LmqD833fOwlaZ14edyT3NtrmwS1U9QHfEUcHSzPRWvP9IcxOrBm+xcmJyJss2uMA0EOiAasHq59Uo7pz1GLAbtSuafB0v5DfeoWJENaLeWawreszeHrZJR5lkxQZAsWvg9/2167SJ7cxlJc7TtWXtIB3cTxJUb2XESNSE2kmbFTRqe9nhyKKAPYZI8t4l3zHS7aJjBFDXni43OtcdjLEAzooU66BSlWGPeZWzFOi9J61LP/QSvrkWweGREETpgj4qVcEeZDDuvtY3BDJj/ovZ3Q== 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=hACV4dnFSXiWJ/ry9NLN404p8Pa80Ae2lDVLVikhDvk=; b=enF9aiuckc6KeEuoCBe9/FXdEF7PopiRK8ITsRQsiFUaU0rNxpTuO0Tz2ik9PjD7T5MaWLRoK9fXiiIoHYEvi2drsFsJrg4BjnZXiBc6p+m60aHr032QjSKBxqT3iXLetV/kw944oJasq585rRGwQYnpRBUXPWGCW8jBnF0ZItE= Received: from MW2PR18MB2171.namprd18.prod.outlook.com (2603:10b6:907:7::17) by SN7PR18MB3997.namprd18.prod.outlook.com (2603:10b6:806:105::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6768.30; Sat, 9 Sep 2023 01:18:08 +0000 Received: from MW2PR18MB2171.namprd18.prod.outlook.com ([fe80::97fd:55db:b72e:500f]) by MW2PR18MB2171.namprd18.prod.outlook.com ([fe80::97fd:55db:b72e:500f%4]) with mapi id 15.20.6768.029; Sat, 9 Sep 2023 01:18:07 +0000 From: Nithin Kumar Dabilpuram To: Sunil Kumar Kori , Thomas Monjalon , Sunil Kumar Kori , Rakesh Kudurumalla CC: "dev@dpdk.org" Subject: RE: [EXT] [PATCH v3 1/1] app/graph: add example for different usecases Thread-Topic: [EXT] [PATCH v3 1/1] app/graph: add example for different usecases Thread-Index: AQHZ4kIj1HLx3ajzFUaQ/+BZxEYqArARsIdg Date: Sat, 9 Sep 2023 01:18:07 +0000 Message-ID: References: <20230425131516.3308612-5-vattunuru@marvell.com> <20230908104907.4060511-1-skori@marvell.com> In-Reply-To: <20230908104907.4060511-1-skori@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+PGF0IG5tPSJib2R5LnR4dCIgcD0iYzpcdXNlcnNcbmRhYmlscHVy?= =?us-ascii?Q?YW1cYXBwZGF0YVxyb2FtaW5nXDA5ZDg0OWI2LTMyZDMtNGE0MC04NWVlLTZi?= =?us-ascii?Q?ODRiYTI5ZTM1Ylxtc2dzXG1zZy1iNjA4NjBjOC00ZWFlLTExZWUtYWYzMi1i?= =?us-ascii?Q?NDZiZmMzZTQ0YzJcYW1lLXRlc3RcYjYwODYwY2EtNGVhZS0xMWVlLWFmMzIt?= =?us-ascii?Q?YjQ2YmZjM2U0NGMyYm9keS50eHQiIHN6PSIxMTg0MTkiIHQ9IjEzMzM4Njk1?= =?us-ascii?Q?ODc5MDY2MzYzMiIgaD0iZmFpeStDaWZsLzc5K3ZpbDN3azZRelduTFRZPSIg?= =?us-ascii?Q?aWQ9IiIgYmw9IjAiIGJvPSIxIiBjaT0iY0FBQUFFUkhVMVJTUlVGTkNnVUFB?= =?us-ascii?Q?TjRQQUFEUUhXTjR1K0xaQWFSZExkODJ6ajQ2cEYwdDN6Yk9Qam9aQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUhBQUFBQnVEd0FBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUVBQVFFQkFBQUE5UmVuTHdDQUFRQUFBQUFBQUFBQUFKNEFBQUJo?= =?us-ascii?Q?QUdRQVpBQnlBR1VBY3dCekFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBRUFBQUFBQUFBQUFnQUFBQUFBbmdBQUFHTUFkUUJ6QUhRQWJ3QnRB?= =?us-ascii?Q?RjhBY0FCbEFISUFjd0J2QUc0QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFBQUFBQUFB?= =?us-ascii?Q?QUFDQUFBQUFBQ2VBQUFBWXdCMUFITUFkQUJ2QUcwQVh3QndBR2dBYndCdUFH?= =?us-ascii?Q?VUFiZ0IxQUcwQVlnQmxBSElBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBaEFBQUFBQUFBQUFBQUFBQUJBQUFBQUFBQUFBSUFBQUFBQUo0QUFB?= =?us-ascii?Q?QmpBSFVBY3dCMEFHOEFiUUJmQUhNQWN3QnVBRjhBWkFCaEFITUFhQUJmQUhZ?= =?us-ascii?Q?QU1BQXlBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= x-dg-refone: =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFQUFBQUFBQUFBQWdBQUFBQUFu?= =?us-ascii?Q?Z0FBQUdNQWRRQnpBSFFBYndCdEFGOEFjd0J6QUc0QVh3QnJBR1VBZVFCM0FH?= =?us-ascii?Q?OEFjZ0JrQUhNQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBUUFBQUFBQUFBQUNBQUFBQUFDZUFBQUFZd0IxQUhNQWRB?= =?us-ascii?Q?QnZBRzBBWHdCekFITUFiZ0JmQUc0QWJ3QmtBR1VBYkFCcEFHMEFhUUIwQUdV?= =?us-ascii?Q?QWNnQmZBSFlBTUFBeUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkFB?= =?us-ascii?Q?QUFBQUFBQUFJQUFBQUFBSjRBQUFCakFIVUFjd0IwQUc4QWJRQmZBSE1BY3dC?= =?us-ascii?Q?dUFGOEFjd0J3QUdFQVl3QmxBRjhBZGdBd0FESUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVBQUFBQUFBQUFBZ0FBQUFB?= =?us-ascii?Q?QW5nQUFBR1FBYkFCd0FGOEFjd0JyQUhrQWNBQmxBRjhBWXdCb0FHRUFkQUJm?= =?us-ascii?Q?QUcwQVpRQnpBSE1BWVFCbkFHVUFYd0IyQURBQU1nQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFRQUFBQUFBQUFBQ0FBQUFBQUNlQUFBQVpBQnNBSEFB?= =?us-ascii?Q?WHdCekFHd0FZUUJqQUdzQVh3QmpBR2dBWVFCMEFGOEFiUUJsQUhNQWN3QmhB?= =?us-ascii?Q?R2NBWlFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= x-dg-reftwo: =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFCQUFBQUFBQUFBQUlBQUFBQUFKNEFBQUJrQUd3?= =?us-ascii?Q?QWNBQmZBSFFBWlFCaEFHMEFjd0JmQUc4QWJnQmxBR1FBY2dCcEFIWUFaUUJm?= =?us-ascii?Q?QUdZQWFRQnNBR1VBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBRUFBQUFBQUFBQUFnQUFBQUFBbmdBQUFHVUFiUUJoQUdrQWJBQmZBR0VB?= =?us-ascii?Q?WkFCa0FISUFaUUJ6QUhNQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFDd0FBQUFBQUFBQUFBQUFBQVFBQUFBQUFBQUFD?= =?us-ascii?Q?QUFBQUFBQ2VBQUFBYlFCaEFISUFkZ0JsQUd3QVh3QndBSElBYndCcUFHVUFZ?= =?us-ascii?Q?d0IwQUY4QWJnQmhBRzBBWlFCekFGOEFZd0J2QUc0QVpnQnBBR1FBWlFCdUFI?= =?us-ascii?Q?UUFhUUJoQUd3QVh3QmhBR3dBYndCdUFHVUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUJBQUFBQUFBQUFBSUFBQUFBQUo0QUFBQnRB?= =?us-ascii?Q?R0VBY2dCMkFHVUFiQUJmQUhBQWNnQnZBR29BWlFCakFIUUFYd0J1QUdFQWJR?= =?us-ascii?Q?QmxBSE1BWHdCeUFHVUFjd0IwQUhJQWFRQmpBSFFBWlFCa0FGOEFZUUJzQUc4?= =?us-ascii?Q?QWJnQmxBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFFQUFBQUFBQUFBQWdBQUFBQUFuZ0FBQUcwQVlRQnlBSFlBWlFCc0FG?= =?us-ascii?Q?OEFjQUJ5QUc4QWFnQmxBR01BZEFCZkFHNEFZUUJ0QUdVQWN3QmZBSElBWlFC?= =?us-ascii?Q?ekFIUUFjZ0JwQUdNQWRBQmxBR1FBWHdCb0FHVUFlQUJqQUc4QVpBQmxBSE1B?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUFBQUFBQUFB?= =?us-ascii?Q?QUNBQUFBQUFDZUFBQUFiUUJoQUhJQWRnQmxBR3dBYkFCZkFHRUFjZ0J0QUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= x-dg-refthree: =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkFBQUFB?= =?us-ascii?Q?QUFBQUFJQUFBQUFBSjRBQUFCdEFHRUFjZ0IyQUdVQWJBQnNBRjhBWndCdkFH?= =?us-ascii?Q?OEFad0JzQUdVQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVBQUFBQUFBQUFBZ0FBQUFBQW5n?= =?us-ascii?Q?QUFBRzBBWVFCeUFIWUFaUUJzQUd3QVh3QndBSElBYndCcUFHVUFZd0IwQUY4?= =?us-ascii?Q?QVl3QnZBR1FBWlFCekFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFRQUFBQUFBQUFBQ0FBQUFBQUNlQUFBQWJRQmhBSElBZGdC?= =?us-ascii?Q?bEFHd0FiQUJmQUhBQWNnQnZBR29BWlFCakFIUUFYd0JqQUc4QVpBQmxBSE1B?= =?us-ascii?Q?WHdCa0FHa0FZd0IwQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQUFB?= =?us-ascii?Q?QUFBQUFBQUlBQUFBQUFKNEFBQUJ0QUdFQWNnQjJBR1VBYkFCc0FGOEFjQUJ5?= =?us-ascii?Q?QUc4QWFnQmxBR01BZEFCZkFHNEFZUUJ0QUdVQWN3QmZBR01BYndCdUFHWUFh?= =?us-ascii?Q?UUJrQUdVQWJnQjBBR2tBWVFCc0FGOEFiUUJoQUhJQWRnQmxBR3dBYkFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUFBQUFBQUFBQUFnQUFBQUFB?= =?us-ascii?Q?bmdBQUFHMEFZUUJ5QUhZQVpRQnNBR3dBWHdCd0FISUFid0JxQUdVQVl3QjBB?= =?us-ascii?Q?RjhBYmdCaEFHMEFaUUJ6QUY4QVl3QnZBRzRBWmdCcEFHUUFaUUJ1QUhRQWFR?= =?us-ascii?Q?QmhBR3dBWHdCdEFHRUFjZ0IyQUdVQWJBQnNBRjhBYndCeUFGOEFZUUJ5QUcw?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= x-dg-reffour: =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFBQUFBQUFBQUFDQUFB?= =?us-ascii?Q?QUFBQ2VBQUFBYlFCaEFISUFkZ0JsQUd3QWJBQmZBSEFBY2dCdkFHb0FaUUJq?= =?us-ascii?Q?QUhRQVh3QnVBR0VBYlFCbEFITUFYd0JqQUc4QWJnQm1BR2tBWkFCbEFHNEFk?= =?us-ascii?Q?QUJwQUdFQWJBQmZBRzBBWVFCeUFIWUFaUUJzQUd3QVh3QnZBSElBWHdCbkFH?= =?us-ascii?Q?OEFid0JuQUd3QVpRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUJBQUFBQUFBQUFBSUFBQUFBQUo0QUFBQnRBR0VB?= =?us-ascii?Q?Y2dCMkFHVUFiQUJzQUY4QWNBQnlBRzhBYWdCbEFHTUFkQUJmQUc0QVlRQnRB?= =?us-ascii?Q?R1VBY3dCZkFISUFaUUJ6QUhRQWNnQnBBR01BZEFCbEFHUUFYd0J0QUdFQWNn?= =?us-ascii?Q?QjJBR1VBYkFCc0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFFQUFBQUFBQUFBQWdBQUFBQUFuZ0FBQUcwQVlRQnlBSFlBWlFCc0FHd0FY?= =?us-ascii?Q?d0J3QUhJQWJ3QnFBR1VBWXdCMEFGOEFiZ0JoQUcwQVpRQnpBRjhBY2dCbEFI?= =?us-ascii?Q?TUFkQUJ5QUdrQVl3QjBBR1VBWkFCZkFHMEFZUUJ5QUhZQVpRQnNBR3dBWHdC?= =?us-ascii?Q?dkFISUFYd0JoQUhJQWJRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUFBQUFBQUFBQUNB?= =?us-ascii?Q?QUFBQUFDZUFBQUFiUUJoQUhJQWRnQmxBR3dBYkFCZkFIUUFaUUJ5QUcwQWFR?= =?us-ascii?Q?QnVBSFVBY3dBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQkFBQUFBQUFBQUFJQUFBQUFBSjRBQUFCdEFH?= =?us-ascii?Q?RUFjZ0IyQUdVQWJBQnNBRjhBZHdCdkFISUFaQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFDRUFBQUFBQUFBQUFB?= =?us-ascii?Q?QUFBQUVBQUFBQUFBQUFBZ0FBQUFBQSIvPjwvbWV0YT4=3D?= x-ms-publictraffictype: Email x-ms-traffictypediagnostic: MW2PR18MB2171:EE_|SN7PR18MB3997:EE_ x-ms-office365-filtering-correlation-id: 45e3cdeb-4f17-4c18-9f39-08dbb0d29fbf x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: HauBtA2EsOeDFu9DpEXH3XIIfG6tR5KEnb8vuttOdec8H8pLsEizNjAemLTx+IhZc8OkYblG6Qj61eugyIxclMln3LEhbTucshfDh2uS27wzJnLrDWGcSM6F7YF/XWyYlsby9LUdyeeaGmDMc4s9FmolItPs9Vr3nK269kce0jtCZCZn5kr5GEQC6Jcd4ID6hQ1MZtN7Kha8urqCxk9CTUObCI6nhCdWT53QNPEqb8pc49+8vt46/NOHxI/B2pAsi9y9NpjPa9PAz4p3U7Fd7rxF1tN9M4TjdiW7xGCgovFnayON3N/DKu8w9/DJuJGnsUy2tKu28sdhSWRxAFY9DsfN0jJge7QSSJDpxUq8aV5JHsyDIzq8HgPduQpnwbKpnov9Sw11oA8Ohbl2u/zupCMTrGYhS6rWQW05YIA+/1V1glbclnWbzskEzXc7tEObqGIM4RCQifeiQywfXRHyL+EkqR91R5YrF0JoueSLth7l2b4UzArVS7BHWN2/8ne1DY7/AEPhR2+FXKA3tKAWlDiFa5NRPPGPB9g/kWYBdktyYfD6SXFCxxEJ+2aX+MoSeIaZPhkiRGm+Yb9vQpCXqJlZeO69hkk3M2ZqC+/gvjVSfLH+MH6uJ+flT5Eo40cR x-forefront-antispam-report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:MW2PR18MB2171.namprd18.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230031)(346002)(136003)(396003)(366004)(39860400002)(376002)(451199024)(186009)(1800799009)(478600001)(5660300002)(19627235002)(6636002)(64756008)(76116006)(66556008)(66946007)(66446008)(66476007)(52536014)(55016003)(83380400001)(30864003)(316002)(2906002)(8936002)(8676002)(4326008)(41300700001)(71200400001)(110136005)(7696005)(53546011)(6506007)(66899024)(9686003)(26005)(122000001)(38100700002)(86362001)(38070700005)(33656002)(579004)(559001)(19607625013); DIR:OUT; SFP:1101; x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?us-ascii?Q?U3A36xd3sYrARFduWMD7wgKh/m9n5DZDBZPVLvQTuaaqDLfGzldy/Bndssp3?= =?us-ascii?Q?0FmerLp77vjMz7FEBRUqEIOJvoS8hQo+OeYTgYteMWFHk5T4pYohRpBisBzm?= =?us-ascii?Q?6OZ3J8ONzHSnJGAA2Yf5kNjICwEOMbCg/sWgAzWjW3BCfDRkBYXKa19Vzcgw?= =?us-ascii?Q?lrCjtM4zB7vi9DTwHC4p875lFH8x0bsNUtHCtYVANZgLp/Oz8FRqyiGS00cI?= =?us-ascii?Q?E6Ak6h/ZDXrwhtj8qjvhl2HA38Ci1316XaQj5yuOPZPcfXnTcxL6XMVX68UU?= =?us-ascii?Q?7COJie0wW+jwMwyalTNmbfH/HENimpjhfSSiN9ZMuO9MfZNeAfqC8j+9I9nx?= =?us-ascii?Q?iCY4+v8qNw5hPjjhZyRNy2aS9oRl0dgZtCOUIIGBozrVBbwgUK3Gy6Z20tb9?= =?us-ascii?Q?KBIXMCre2328b9m/eRZpUX17EQSHhKvbC+xG2zPdBb3CXbXfnljM+gVs6i6F?= =?us-ascii?Q?c+bCaqvjaEMWiLCd8XKaIbpfs0B5HJ9ZSnOUi2zauGa73hUSnW11XmFDA17N?= =?us-ascii?Q?MLW36sdGg5IsrRxQv+xczMncZxThaKJrQtjaO9HfT3bt/tFPUJao19dc86ij?= =?us-ascii?Q?JDcsOD5T3Vh//Sf+mgVmzjiyUsGBRospowFDsoXm28LRjV7NCK8tk3ZFVqps?= =?us-ascii?Q?ZEbqn5nw59FWEQE9eZaiBs4+nSZS0Gu1p+w1Fv2lNW9k50ivlTGh4yuMnQXU?= =?us-ascii?Q?y0hVxtvfKs55zORKmO9/xizaZ04LBJIktMM5PrsbD+KFFC3X2hBWrTZovth5?= =?us-ascii?Q?ZteyxVqRzoKKWGa31JIzjyALdHr81PBpoi/bB2rwEKcR0RMwzItxfkRc373V?= =?us-ascii?Q?l0ZztHMV+KRAZW8C1MV5EFSW9FhdcDVFy+XSO+nAG30gNzMtWMyFO69lmgcU?= =?us-ascii?Q?YSlvtjGOJbR3+hQsSjwwBV4OvfadPpzAAWWVJq59uBVjkGn404/8xO88sxJG?= =?us-ascii?Q?vTJDWO3TdOWztFtpjatBMczd69K20tIRp6A8rQeYGqIyfyFrlETt00g1gJ+t?= =?us-ascii?Q?T9GcXaZ4quE0LGMHk6cP9fBD07DpykRbndPXFLELWRKdpTaFeMzlUrPDEAPK?= =?us-ascii?Q?YhtF541tx8WUspe4slzr1yB+OW03aUQ/dAPKa0hXo+fOOMLsYytERWlLwK56?= =?us-ascii?Q?CKxqToRwp6hZWkOU6WYz+EcfU8GM7H6ddrEhKFjfb//R7WLrmzkMVzr2wtJu?= =?us-ascii?Q?HKbDN6spxJEzSwxQWx8R6txPfJ+eMX3UiitKZHdYZ3lCfZEKLHkNorCaR3zS?= =?us-ascii?Q?AWpzibBUsLw409RD5bkqdXKVc5ZSr//X8oR6dzCT7fndjGhXUbJNjV8va36W?= =?us-ascii?Q?2ry8pxlyxl9MHz5/0EYYX92FOKMeMqeNqrXhBrHEgUJAgn3Q3bHuUB9dLAs6?= =?us-ascii?Q?g8xMZIytbMk2xOXeCbI3+IkLy64e1y/XQb/jf93VxEhM2E0CC5KMep4vzQ48?= =?us-ascii?Q?ZYMea2pyVgPckJ4qMEQOgiZi+X0/VViYXJ30xWTYjdk+lcxt0jG5UaPnxFOP?= =?us-ascii?Q?rnufLiPpfcwV8ixV5M19lZnKunS9/CGi9OTqMsqtiYsRe3ebyaO3AlWTNrdM?= =?us-ascii?Q?33BIkr+VK9eNJl5YN50HkFcOnrLKbOQw95boShnc?= 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: MW2PR18MB2171.namprd18.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 45e3cdeb-4f17-4c18-9f39-08dbb0d29fbf X-MS-Exchange-CrossTenant-originalarrivaltime: 09 Sep 2023 01:18:07.2508 (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: GrzOBi2CXPzjGVqK7yfu+MdkNEA6ccmoAFeOWVla42kcjZspMdpoge+SUcUfna4fa86TmCGfbA4QTH00lI2SSA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN7PR18MB3997 X-Proofpoint-ORIG-GUID: taxXj1HSlVijT-5ftkBfQmu3eSFJ-4ph X-Proofpoint-GUID: taxXj1HSlVijT-5ftkBfQmu3eSFJ-4ph X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.267,Aquarius:18.0.957,Hydra:6.0.601,FMLib:17.11.176.26 definitions=2023-09-09_01,2023-09-05_01,2023-05-22_02 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 Please see inline. > -----Original Message----- > From: skori@marvell.com > Sent: Friday, September 8, 2023 4:19 PM > To: Thomas Monjalon ; Sunil Kumar Kori ; > Rakesh Kudurumalla > Cc: dev@dpdk.org > Subject: [EXT] [PATCH v3 1/1] app/graph: add example for different usecas= es >=20 > External Email >=20 > ---------------------------------------------------------------------- > From: Sunil Kumar Kori >=20 > Current l3fwd-graph application only validates l3fwd use case. > To scale up this, new application will be added with a framework > to run as user's provided usecases. >=20 > Required configuration and use cases details are fetched via a > static .cli file which will be used to create a graph for > requested uscases. >=20 > Signed-off-by: Sunil Kumar Kori > Signed-off-by: Rakesh Kudurumalla > --- > MAINTAINERS | 7 + > app/graph/cli.c | 208 ++++++ > app/graph/cli.h | 48 ++ > app/graph/cli_priv.h | 19 + > app/graph/conn.c | 284 +++++++++ > app/graph/conn.h | 46 ++ > app/graph/ethdev.c | 632 +++++++++++++++++++ > app/graph/ethdev.h | 28 + > app/graph/ethdev_priv.h | 46 ++ > app/graph/ethdev_rx.c | 139 ++++ > app/graph/ethdev_rx.h | 32 + > app/graph/ethdev_rx_priv.h | 23 + > app/graph/examples/l3fwd.cli | 87 +++ > app/graph/graph.c | 383 +++++++++++ > app/graph/graph.h | 11 + > app/graph/graph_priv.h | 32 + > app/graph/ip4_route.c | 146 +++++ > app/graph/ip6_route.c | 154 +++++ > app/graph/l3fwd.c | 152 +++++ > app/graph/l3fwd.h | 11 + > app/graph/main.c | 201 ++++++ > app/graph/mempool.c | 134 ++++ > app/graph/mempool.h | 18 + > app/graph/mempool_priv.h | 16 + > app/graph/meson.build | 25 + > app/graph/module_api.h | 33 + > app/graph/neigh.c | 269 ++++++++ > app/graph/neigh.h | 11 + > app/graph/neigh_priv.h | 22 + > app/graph/route.h | 30 + > app/graph/utils.c | 155 +++++ > app/graph/utils.h | 14 + > app/meson.build | 1 + > doc/guides/tools/graph.rst | 171 +++++ > doc/guides/tools/img/graph-usecase-l3fwd.svg | 210 ++++++ > doc/guides/tools/index.rst | 1 + > 36 files changed, 3799 insertions(+) > create mode 100644 app/graph/cli.c > create mode 100644 app/graph/cli.h > create mode 100644 app/graph/cli_priv.h > create mode 100644 app/graph/conn.c > create mode 100644 app/graph/conn.h > create mode 100644 app/graph/ethdev.c > create mode 100644 app/graph/ethdev.h > create mode 100644 app/graph/ethdev_priv.h > create mode 100644 app/graph/ethdev_rx.c > create mode 100644 app/graph/ethdev_rx.h > create mode 100644 app/graph/ethdev_rx_priv.h > create mode 100644 app/graph/examples/l3fwd.cli > create mode 100644 app/graph/graph.c > create mode 100644 app/graph/graph.h > create mode 100644 app/graph/graph_priv.h > create mode 100644 app/graph/ip4_route.c > create mode 100644 app/graph/ip6_route.c > create mode 100644 app/graph/l3fwd.c > create mode 100644 app/graph/l3fwd.h > create mode 100644 app/graph/main.c > create mode 100644 app/graph/mempool.c > create mode 100644 app/graph/mempool.h > create mode 100644 app/graph/mempool_priv.h > create mode 100644 app/graph/meson.build > create mode 100644 app/graph/module_api.h > create mode 100644 app/graph/neigh.c > create mode 100644 app/graph/neigh.h > create mode 100644 app/graph/neigh_priv.h > create mode 100644 app/graph/route.h > create mode 100644 app/graph/utils.c > create mode 100644 app/graph/utils.h > create mode 100644 doc/guides/tools/graph.rst > create mode 100644 doc/guides/tools/img/graph-usecase-l3fwd.svg >=20 [Nithin] Split to multiple smaller patches > diff --git a/MAINTAINERS b/MAINTAINERS > index 698608cdb2..7f149bd060 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -1806,6 +1806,13 @@ F: dts/ > F: devtools/dts-check-format.sh > F: doc/guides/tools/dts.rst >=20 > +Graph application > +M: Sunil Kumar Kori > +M: Rakesh Kudurumalla > +F: app/graph/ > +F: doc/guides/tools/graph.rst > +F: doc/guides/tools/img/graph-usecase-l3fwd.svg > + >=20 > Other Example Applications > -------------------------- > diff --git a/app/graph/cli.c b/app/graph/cli.c > new file mode 100644 > index 0000000000..237fa8008f > --- /dev/null > +++ b/app/graph/cli.c > @@ -0,0 +1,208 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > + > +#include "cli_priv.h" > +#include "module_api.h" > + > +#define CMD_MAX_TOKENS 256 > +#define MAX_LINE_SIZE 2048 > + > +static struct cli_node_head module_list =3D STAILQ_HEAD_INITIALIZER(modu= le_list); > + > +#define PARSE_DELIMITER " \f\n\r\t\v" > + > +static int > +tokenize_string_parse(char *string, char *tokens[], uint32_t *n_tokens) > +{ > + uint32_t i; > + > + if ((string =3D=3D NULL) || > + (tokens =3D=3D NULL) || > + (*n_tokens < 1)) > + return -EINVAL; > + > + for (i =3D 0; i < *n_tokens; i++) { > + tokens[i] =3D strtok_r(string, PARSE_DELIMITER, &string); > + if (tokens[i] =3D=3D NULL) > + break; > + } > + > + if ((i =3D=3D *n_tokens) && strtok_r(string, PARSE_DELIMITER, &string)) > + return -E2BIG; > + > + *n_tokens =3D i; > + return 0; > +} > + > +static int > +is_comment(char *in) > +{ > + if ((strlen(in) && index("!#%;", in[0])) || > + (strncmp(in, "//", 2) =3D=3D 0) || > + (strncmp(in, "--", 2) =3D=3D 0)) > + return 1; > + > + return 0; > +} > + > +static bool > +module_list_has_cmd_registered(const char *cmd) > +{ > + struct cli_node *node; > + > + STAILQ_FOREACH(node, &module_list, next) { > + if (strcmp(node->cmd, cmd) =3D=3D 0) { > + rte_errno =3D EEXIST; > + return 1; > + } > + } > + return 0; > +} > + > +void > +cli_module_register(const struct cli_module *module) > +{ > + struct cli_node *node; > + > + /* Check sanity */ > + if (module =3D=3D NULL || module->process =3D=3D NULL) { > + rte_errno =3D EINVAL; > + return; > + } > + > + /* Check for duplicate name */ > + if (module_list_has_cmd_registered(module->cmd)) { > + printf("module %s is already registered\n", module->cmd); > + return; > + } > + > + node =3D malloc(sizeof(struct cli_node)); > + if (node =3D=3D NULL) { > + rte_errno =3D ENOMEM; > + return; > + } > + > + /* Initialize the node */ > + if (rte_strscpy(node->cmd, module->cmd, APP_CLI_CMD_NAME_SIZE) < 0) { > + free(node); > + return; > + } > + node->process =3D module->process; > + node->usage =3D module->usage; > + > + /* Add the node at tail */ > + STAILQ_INSERT_TAIL(&module_list, node, next); > +} > + > +void > +cli_process(char *in, char *out, size_t out_size, void *obj) > +{ > + char *tokens[CMD_MAX_TOKENS]; > + struct cli_node *node; > + uint32_t n_tokens; > + int rc; > + > + if (is_comment(in)) > + return; > + > + n_tokens =3D RTE_DIM(tokens); > + rc =3D tokenize_string_parse(in, tokens, &n_tokens); > + if (rc) { > + snprintf(out, out_size, MSG_ARG_TOO_MANY, ""); > + return; > + } > + > + if (n_tokens =3D=3D 0) > + return; > + > + if ((n_tokens =3D=3D 1) && strcmp(tokens[0], "help") =3D=3D 0) { > + STAILQ_FOREACH(node, &module_list, next) { > + node->usage(tokens, n_tokens, out, out_size, obj); > + } > + return; > + } > + > + if ((n_tokens >=3D 2) && strcmp(tokens[0], "help") =3D=3D 0) { > + STAILQ_FOREACH(node, &module_list, next) { > + if (strcmp(node->cmd, tokens[1]) =3D=3D 0) { > + node->usage(tokens, n_tokens, out, out_size, obj); > + return; > + } > + } > + snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]); > + return; > + } > + > + STAILQ_FOREACH(node, &module_list, next) { > + if (strcmp(node->cmd, tokens[0]) =3D=3D 0) { > + rc =3D node->process(tokens, n_tokens, out, out_size, obj); > + if (rc < 0) > + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); > + > + return; > + } > + } > + > + snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]); > +} > + > +int > +cli_script_process(const char *file_name, size_t msg_in_len_max, size_t > msg_out_len_max, void *obj) > +{ > + char *msg_in =3D NULL, *msg_out =3D NULL; > + FILE *f =3D NULL; > + > + /* Check input arguments */ > + if ((file_name =3D=3D NULL) || (strlen(file_name) =3D=3D 0) || (msg_in_= len_max =3D=3D 0) || > + (msg_out_len_max =3D=3D 0)) > + return -EINVAL; > + > + msg_in =3D malloc(msg_in_len_max + 1); > + msg_out =3D malloc(msg_out_len_max + 1); > + if ((msg_in =3D=3D NULL) || (msg_out =3D=3D NULL)) { > + free(msg_out); > + free(msg_in); > + return -ENOMEM; > + } > + > + /* Open input file */ > + f =3D fopen(file_name, "r"); > + if (f =3D=3D NULL) { > + free(msg_out); > + free(msg_in); > + return -EIO; > + } > + > + /* Read file */ > + while (1) { > + if (fgets(msg_in, msg_in_len_max + 1, f) =3D=3D NULL) > + break; > + > + msg_out[0] =3D 0; > + > + cli_process(msg_in, msg_out, msg_out_len_max, obj); > + > + if (strlen(msg_out)) > + printf("%s", msg_out); > + } > + > + /* Close file */ > + fclose(f); > + free(msg_out); > + free(msg_in); > + return 0; > +} > diff --git a/app/graph/cli.h b/app/graph/cli.h > new file mode 100644 > index 0000000000..2bd89f3d1f > --- /dev/null > +++ b/app/graph/cli.h > @@ -0,0 +1,48 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#ifndef APP_GRAPH_CLI_H > +#define APP_GRAPH_CLI_H > + > +/* Macros */ > +#define MSG_OUT_OF_MEMORY "Not enough memory.\n" > +#define MSG_CMD_UNKNOWN "Unknown command \"%s\".\n" > +#define MSG_CMD_UNIMPLEM "Command \"%s\" not implemented.\n" > +#define MSG_ARG_NOT_ENOUGH "Not enough arguments for command \"%s\".\n" > +#define MSG_ARG_TOO_MANY "Too many arguments for command \"%s\".\n" > +#define MSG_ARG_MISMATCH "Wrong number of arguments for command \"%s\= ".\n" > +#define MSG_ARG_NOT_FOUND "Argument \"%s\" not found.\n" > +#define MSG_ARG_INVALID "Invalid value for argument \"%s\".\n" > +#define MSG_FILE_ERR "Error in file \"%s\" at line %u.\n" > +#define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n" > +#define MSG_CMD_FAIL "Command \"%s\" failed.\n" > + > +#define APP_CLI_CMD_NAME_SIZE 64 > + > +/* Typedefs */ > +typedef int (*cli_module_t)(char **tokens, uint32_t n_tokens, char *out,= size_t out_size, > + void *obj); > + > +/* Structures */ > +struct cli_module { > + char cmd[APP_CLI_CMD_NAME_SIZE]; /**< Name of the command to be > registered. */ > + cli_module_t process; /**< Command process function. */ > + cli_module_t usage; /**< Help command process function. */ > +}; > + > +/* APIs */ > +void cli_module_register(const struct cli_module *module); > + > +#define CLI_REGISTER(module) \ > + RTE_INIT(cli_register_##module) \ > + { \ > + cli_module_register(&module); \ > + } > + > +void cli_process(char *in, char *out, size_t out_size, void *arg); > + > +int cli_script_process(const char *file_name, size_t msg_in_len_max, siz= e_t > msg_out_len_max, > + void *arg); > + > +#endif > diff --git a/app/graph/cli_priv.h b/app/graph/cli_priv.h > new file mode 100644 > index 0000000000..9ecc89c353 > --- /dev/null > +++ b/app/graph/cli_priv.h > @@ -0,0 +1,19 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#ifndef APP_GRAPH_CLI_PRIV_H > +#define APP_GRAPH_CLI_PRIV_H > + > +#include "cli.h" > + > +struct cli_node { > + STAILQ_ENTRY(cli_node) next; /**< Next node in the list. */ > + char cmd[APP_CLI_CMD_NAME_SIZE]; /**< Name of the command. */ > + cli_module_t process; /**< Command process function. */ > + cli_module_t usage; /**< Help command process function. */ > +}; > + > +STAILQ_HEAD(cli_node_head, cli_node); > + > +#endif > diff --git a/app/graph/conn.c b/app/graph/conn.c > new file mode 100644 > index 0000000000..dabc8deca2 > --- /dev/null > +++ b/app/graph/conn.c > @@ -0,0 +1,284 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "module_api.h" > + > +#define MSG_CMD_TOO_LONG "Command too long." > + > +static int > +data_event_handle(struct conn *conn, int fd_client) > +{ > + ssize_t len, i, rc =3D 0; > + > + /* Read input message */ > + len =3D read(fd_client, conn->buf, conn->buf_size); > + if (len =3D=3D -1) { > + if ((errno =3D=3D EAGAIN) || (errno =3D=3D EWOULDBLOCK)) > + return 0; > + > + return -1; > + } > + > + if (len =3D=3D 0) > + return rc; > + > + /* Handle input messages */ > + for (i =3D 0; i < len; i++) { > + if (conn->buf[i] =3D=3D '\n') { > + size_t n; > + > + conn->msg_in[conn->msg_in_len] =3D 0; > + conn->msg_out[0] =3D 0; > + > + conn->msg_handle(conn->msg_in, conn->msg_out, conn- > >msg_out_len_max, > + conn->msg_handle_arg); > + > + n =3D strlen(conn->msg_out); > + if (n) { > + rc =3D write(fd_client, conn->msg_out, n); > + if (rc =3D=3D -1) > + goto exit; > + } > + > + conn->msg_in_len =3D 0; > + } else if (conn->msg_in_len < conn->msg_in_len_max) { > + conn->msg_in[conn->msg_in_len] =3D conn->buf[i]; > + conn->msg_in_len++; > + } else { > + rc =3D write(fd_client, MSG_CMD_TOO_LONG, > strlen(MSG_CMD_TOO_LONG)); > + if (rc =3D=3D -1) > + goto exit; > + > + conn->msg_in_len =3D 0; > + } > + } > + > + /* Write prompt */ > + rc =3D write(fd_client, conn->prompt, strlen(conn->prompt)); > + rc =3D (rc =3D=3D -1) ? -1 : 0; > + > +exit: > + return rc; > +} > + > +static int > +control_event_handle(struct conn *conn, int fd_client) > +{ > + int rc; > + > + rc =3D epoll_ctl(conn->fd_client_group, EPOLL_CTL_DEL, fd_client, NULL)= ; > + if (rc =3D=3D -1) > + goto exit; > + > + rc =3D close(fd_client); > + if (rc =3D=3D -1) > + goto exit; > + > + rc =3D 0; > + > +exit: > + return rc; > +} > + > +struct conn * > +conn_init(struct conn_params *p) > +{ > + int fd_server, fd_client_group, rc; > + struct sockaddr_in server_address; > + struct conn *conn =3D NULL; > + > + memset(&server_address, 0, sizeof(server_address)); > + > + /* Check input arguments */ > + if ((p =3D=3D NULL) || (p->welcome =3D=3D NULL) || (p->prompt =3D=3D NU= LL) || (p->addr =3D=3D > NULL) || > + (p->buf_size =3D=3D 0) || (p->msg_in_len_max =3D=3D 0) || (p->msg_o= ut_len_max =3D=3D 0) > || > + (p->msg_handle =3D=3D NULL)) > + goto exit; > + > + rc =3D inet_aton(p->addr, &server_address.sin_addr); > + if (rc =3D=3D 0) > + goto exit; > + > + /* Memory allocation */ > + conn =3D calloc(1, sizeof(struct conn)); > + if (conn =3D=3D NULL) > + goto exit; > + > + conn->welcome =3D calloc(1, CONN_WELCOME_LEN_MAX + 1); > + conn->prompt =3D calloc(1, CONN_PROMPT_LEN_MAX + 1); > + conn->buf =3D calloc(1, p->buf_size); > + conn->msg_in =3D calloc(1, p->msg_in_len_max + 1); > + conn->msg_out =3D calloc(1, p->msg_out_len_max + 1); > + > + if ((conn->welcome =3D=3D NULL) || (conn->prompt =3D=3D NULL) || (conn-= >buf =3D=3D NULL) > || > + (conn->msg_in =3D=3D NULL) || (conn->msg_out =3D=3D NULL)) { > + conn_free(conn); > + conn =3D NULL; > + goto exit; > + } > + > + /* Server socket */ > + server_address.sin_family =3D AF_INET; > + server_address.sin_port =3D htons(p->port); > + > + fd_server =3D socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); > + if (fd_server =3D=3D -1) { > + conn_free(conn); > + conn =3D NULL; > + goto exit; > + } > + > + rc =3D bind(fd_server, (struct sockaddr *)&server_address, sizeof(serve= r_address)); > + if (rc =3D=3D -1) { > + conn_free(conn); > + close(fd_server); > + conn =3D NULL; > + goto exit; > + } > + > + rc =3D listen(fd_server, 16); > + if (rc =3D=3D -1) { > + conn_free(conn); > + close(fd_server); > + conn =3D NULL; > + goto exit; > + } > + > + /* Client group */ > + fd_client_group =3D epoll_create(1); > + if (fd_client_group =3D=3D -1) { > + conn_free(conn); > + close(fd_server); > + conn =3D NULL; > + goto exit; > + } > + > + /* Fill in */ > + strncpy(conn->welcome, p->welcome, CONN_WELCOME_LEN_MAX); > + strncpy(conn->prompt, p->prompt, CONN_PROMPT_LEN_MAX); > + conn->buf_size =3D p->buf_size; > + conn->msg_in_len_max =3D p->msg_in_len_max; > + conn->msg_out_len_max =3D p->msg_out_len_max; > + conn->msg_in_len =3D 0; > + conn->fd_server =3D fd_server; > + conn->fd_client_group =3D fd_client_group; > + conn->msg_handle =3D p->msg_handle; > + conn->msg_handle_arg =3D p->msg_handle_arg; > + > +exit: > + return conn; > +} > + > +void > +conn_free(struct conn *conn) > +{ > + if (conn =3D=3D NULL) > + return; > + > + if (conn->fd_client_group) > + close(conn->fd_client_group); > + > + if (conn->fd_server) > + close(conn->fd_server); > + > + free(conn->msg_out); > + free(conn->msg_in); > + free(conn->prompt); > + free(conn->welcome); > + free(conn); > +} > + > +int > +conn_req_poll(struct conn *conn) > +{ > + struct sockaddr_in client_address; > + socklen_t client_address_length; > + struct epoll_event event; > + int fd_client, rc; > + > + /* Check input arguments */ > + if (conn =3D=3D NULL) > + return -1; > + > + /* Server socket */ > + client_address_length =3D sizeof(client_address); > + fd_client =3D accept4(conn->fd_server, (struct sockaddr *)&client_addre= ss, > + &client_address_length, SOCK_NONBLOCK); > + if (fd_client =3D=3D -1) { > + if ((errno =3D=3D EAGAIN) || (errno =3D=3D EWOULDBLOCK)) > + return 0; > + > + return -1; > + } > + > + /* Client group */ > + event.events =3D EPOLLIN | EPOLLRDHUP | EPOLLHUP; > + event.data.fd =3D fd_client; > + > + rc =3D epoll_ctl(conn->fd_client_group, EPOLL_CTL_ADD, fd_client, &even= t); > + if (rc =3D=3D -1) { > + close(fd_client); > + goto exit; > + } > + > + /* Client */ > + rc =3D write(fd_client, conn->welcome, strlen(conn->welcome)); > + if (rc =3D=3D -1) { > + close(fd_client); > + goto exit; > + } > + > + rc =3D write(fd_client, conn->prompt, strlen(conn->prompt)); > + if (rc =3D=3D -1) { > + close(fd_client); > + goto exit; > + } > + > + rc =3D 0; > + > +exit: > + return rc; > +} > + > +int > +conn_msg_poll(struct conn *conn) > +{ > + int fd_client, rc, rc_data =3D 0, rc_control =3D 0; > + struct epoll_event event; > + > + /* Check input arguments */ > + if (conn =3D=3D NULL) > + return -1; > + > + /* Client group */ > + rc =3D epoll_wait(conn->fd_client_group, &event, 1, 0); > + if ((rc =3D=3D -1) || rc =3D=3D 0) > + return rc; > + > + fd_client =3D event.data.fd; > + > + /* Data available */ > + if (event.events & EPOLLIN) > + rc_data =3D data_event_handle(conn, fd_client); > + > + /* Control events */ > + if (event.events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP)) > + rc_control =3D control_event_handle(conn, fd_client); > + > + if (rc_data || rc_control) > + return -1; > + > + return 0; > +} > diff --git a/app/graph/conn.h b/app/graph/conn.h > new file mode 100644 > index 0000000000..770964cf4c > --- /dev/null > +++ b/app/graph/conn.h > @@ -0,0 +1,46 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#ifndef APP_GRAPH_CONN_H > +#define APP_GRAPH_CONN_H > + > +#define CONN_WELCOME_LEN_MAX 1024 > +#define CONN_PROMPT_LEN_MAX 16 > + > +typedef void (*conn_msg_handle_t)(char *msg_in, char *msg_out, size_t > msg_out_len_max, void *arg); > + > +struct conn { > + char *welcome; > + char *prompt; > + char *buf; > + char *msg_in; > + char *msg_out; > + size_t buf_size; > + size_t msg_in_len_max; > + size_t msg_out_len_max; > + size_t msg_in_len; > + int fd_server; > + int fd_client_group; > + conn_msg_handle_t msg_handle; > + void *msg_handle_arg; > +}; > + > +struct conn_params { > + const char *welcome; > + const char *prompt; > + const char *addr; > + uint16_t port; > + size_t buf_size; > + size_t msg_in_len_max; > + size_t msg_out_len_max; > + conn_msg_handle_t msg_handle; > + void *msg_handle_arg; > +}; > + > +struct conn *conn_init(struct conn_params *p); > +void conn_free(struct conn *conn); > +int conn_req_poll(struct conn *conn); > +int conn_msg_poll(struct conn *conn); > + > +#endif > diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c > new file mode 100644 > index 0000000000..840a8ca42f > --- /dev/null > +++ b/app/graph/ethdev.c > @@ -0,0 +1,632 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#include > +#include > +#include > + > +#include > +#include > +#include > + > +#include "ethdev_priv.h" > +#include "module_api.h" > + > +static const char > +cmd_ethdev_mtu_help[] =3D "ethdev mtu "; > + > +static const char > +cmd_ethdev_prom_mode_help[] =3D "ethdev promiscuous "; > + > +static const char > +cmd_ethdev_help[] =3D "ethdev rxq txq > " > + "[mtu ]"; > +static const char > +cmd_ethdev_show_help[] =3D "ethdev show"; > + > +static const char > +cmd_ethdev_ip4_addr_help[] =3D "ethdev ip4 addr add n= etmask > "; > + > +static const char > +cmd_ethdev_ip6_addr_help[] =3D "ethdev ip6 addr add n= etmask > "; > + > +static struct rte_eth_conf port_conf_default =3D { > + .link_speeds =3D 0, > + .rxmode =3D { > + .mq_mode =3D RTE_ETH_MQ_RX_NONE, > + .mtu =3D 9000 - (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN), /* Jumbo > frame MTU */ > + }, > + .rx_adv_conf =3D { > + .rss_conf =3D { > + .rss_key =3D NULL, > + .rss_key_len =3D 40, > + .rss_hf =3D 0, > + }, > + }, > + .txmode =3D { > + .mq_mode =3D RTE_ETH_MQ_TX_NONE, > + }, > + .lpbk_mode =3D 0, > +}; > + > +uint32_t enabled_port_mask; > +struct ethdev port_list[RTE_MAX_ETHPORTS]; > + > +void * > +ethdev_mempool_list_by_portid(uint16_t portid) > +{ > + if (portid >=3D RTE_MAX_ETHPORTS) > + return NULL; > + > + return &port_list[portid].config.rx.mp; > +} > + > +int16_t > +ethdev_portid_by_ip4(uint32_t ip) > +{ > + int portid =3D -EINVAL; > + int i; > + > + for (i =3D 0; i < RTE_MAX_ETHPORTS; i++) { > + if ((port_list[i].ip4_addr.ip & route4[i].netmask) =3D=3D (ip & > route4[i].netmask)) > + break; > + } > + > + if (i =3D=3D RTE_MAX_ETHPORTS) > + return portid; > + > + return port_list[i].config.port_id; > +} > + > +int16_t > +ethdev_portid_by_ip6(uint8_t *ip) > +{ > + int portid =3D -EINVAL; > + int i, j; > + > + for (i =3D 0; i < RTE_MAX_ETHPORTS; i++) { > + for (j =3D 0; j < ETHDEV_IPV6_ADDR_LEN; j++) { > + if ((port_list[i].ip6_addr.ip[j] & route6[i].mask[j]) !=3D > + (ip[j] & route6[i].mask[j])) > + break; > + } > + > + if (j =3D=3D ETHDEV_IPV6_ADDR_LEN) > + break; > + } > + > + if (i =3D=3D RTE_MAX_ETHPORTS) > + return portid; > + > + return port_list[i].config.port_id; > +} > + > +void > +ethdev_stop(void) > +{ > + uint16_t portid; > + int rc; > + > + RTE_ETH_FOREACH_DEV(portid) { > + if ((enabled_port_mask & (1 << portid)) =3D=3D 0) > + continue; > + printf("Closing port %d...", portid); > + rc =3D rte_eth_dev_stop(portid); > + if (rc !=3D 0) > + printf("Failed to stop port %u: %s\n", > + portid, rte_strerror(-rc)); > + rte_eth_dev_close(portid); > + printf(" Done\n"); > + } > + > + /* clean up the EAL */ > + rte_eal_cleanup(); > + printf("Bye...\n"); > +} > + > +void > +ethdev_start(void) > +{ > + uint16_t portid; > + int rc; > + > + RTE_ETH_FOREACH_DEV(portid) > + { > + if ((enabled_port_mask & (1 << portid)) =3D=3D 0) > + continue; > + > + rc =3D rte_eth_dev_start(portid); > + if (rc < 0) > + rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=3D%d, port=3D%d\n", > rc, portid); > + } > +} > + > + > +static int > +ethdev_show(const char *name, char **out, size_t *out_size) > +{ > + uint16_t mtu =3D 0, port_id =3D 0; > + struct rte_eth_dev_info info; > + struct rte_eth_stats stats; > + struct rte_ether_addr addr; > + struct rte_eth_link link; > + uint32_t length; > + int rc; > + > + rc =3D rte_eth_dev_get_port_by_name(name, &port_id); > + if (rc < 0) > + return rc; > + > + rte_eth_dev_info_get(port_id, &info); > + rte_eth_stats_get(port_id, &stats); > + rte_eth_macaddr_get(port_id, &addr); > + rte_eth_link_get(port_id, &link); > + rte_eth_dev_get_mtu(port_id, &mtu); > + > + snprintf(*out, *out_size, > + "%s: flags=3D<%s> mtu %u\n" > + "\tether " RTE_ETHER_ADDR_PRT_FMT " rxqueues %u txqueues %u\n" > + "\tport# %u speed %s\n" > + "\tRX packets %" PRIu64" bytes %" PRIu64"\n" > + "\tRX errors %" PRIu64" missed %" PRIu64" no-mbuf %" PRIu64"\n" > + "\tTX packets %" PRIu64" bytes %" PRIu64"\n" > + "\tTX errors %" PRIu64"\n\n", > + name, > + link.link_status ? "UP" : "DOWN", > + mtu, > + RTE_ETHER_ADDR_BYTES(&addr), > + info.nb_rx_queues, > + info.nb_tx_queues, > + port_id, > + rte_eth_link_speed_to_str(link.link_speed), > + stats.ipackets, > + stats.ibytes, > + stats.ierrors, > + stats.imissed, > + stats.rx_nombuf, > + stats.opackets, > + stats.obytes, > + stats.oerrors); > + > + length =3D strlen(*out); > + *out_size -=3D length; > + *out +=3D length; > + return 0; > +} > + > +static int > +ethdev_ip4_addr_add(const char *name, struct ipv4_addr_config *config) > +{ > + uint16_t portid =3D 0; > + int rc; > + > + rc =3D rte_eth_dev_get_port_by_name(name, &portid); > + if (rc < 0) > + return rc; > + > + port_list[portid].ip4_addr.ip =3D config->ip; > + port_list[portid].ip4_addr.mask =3D config->mask; > + return 0; > +} > + > +static int > +ethdev_ip6_addr_add(const char *name, struct ipv6_addr_config *config) > +{ > + uint16_t portid =3D 0; > + int rc, i; > + > + rc =3D rte_eth_dev_get_port_by_name(name, &portid); > + if (rc < 0) > + return rc; > + > + for (i =3D 0; i < ETHDEV_IPV6_ADDR_LEN; i++) { > + port_list[portid].ip6_addr.ip[i] =3D config->ip[i]; > + port_list[portid].ip6_addr.mask[i] =3D config->mask[i]; > + } > + > + return 0; > +} > + > +static int > +ethdev_prom_mode_config(const char *name, bool enable) > +{ > + uint16_t portid =3D 0; > + int rc; > + > + rc =3D rte_eth_dev_get_port_by_name(name, &portid); > + if (rc < 0) > + return rc; > + > + if (enable) > + rc =3D rte_eth_promiscuous_enable(portid); > + else > + rc =3D rte_eth_promiscuous_disable(portid); > + > + if (rc < 0) > + return rc; > + > + port_list[portid].config.promiscuous =3D enable; > + return 0; > +} > + > +static int > +ethdev_mtu_config(const char *name, uint32_t mtu) > +{ > + uint16_t portid =3D 0; > + int rc; > + > + rc =3D rte_eth_dev_get_port_by_name(name, &portid); > + if (rc < 0) > + return rc; > + > + rc =3D rte_eth_dev_set_mtu(portid, mtu); > + if (rc < 0) > + return rc; > + > + port_list[portid].config.mtu =3D mtu; > + return 0; > +} > + > +static int > +ethdev_process(const char *name, struct ethdev_config *params) > +{ > + struct rte_eth_dev_info port_info; > + struct rte_eth_conf port_conf; > + struct ethdev_rss_config *rss; > + struct rte_mempool *mempool; > + struct rte_ether_addr smac; > + int numa_node, rc; > + uint16_t port_id =3D 0; > + uint32_t i; > + > + /* Check input params */ > + if (!name || !name[0] || !params || !params->rx.n_queues || !params- > >rx.queue_size || > + !params->tx.n_queues || !params->tx.queue_size) > + return -EINVAL; > + > + rc =3D rte_eth_dev_get_port_by_name(name, &port_id); > + if (rc) > + return -EINVAL; > + > + rc =3D rte_eth_dev_info_get(port_id, &port_info); > + if (rc) > + return -EINVAL; > + > + mempool =3D rte_mempool_lookup(params->rx.mempool_name); > + if (!mempool) > + return -EINVAL; > + > + params->rx.mp =3D mempool; > + > + rss =3D params->rx.rss; > + if (rss) { > + if (!port_info.reta_size || port_info.reta_size > > RTE_ETH_RSS_RETA_SIZE_512) > + return -EINVAL; > + > + if (!rss->n_queues || rss->n_queues >=3D ETHDEV_RXQ_RSS_MAX) > + return -EINVAL; > + > + for (i =3D 0; i < rss->n_queues; i++) > + if (rss->queue_id[i] >=3D port_info.max_rx_queues) > + return -EINVAL; > + } > + > + /* Port */ > + memcpy(&port_conf, &port_conf_default, sizeof(struct rte_eth_conf)); > + if (rss) { > + uint64_t rss_hf =3D RTE_ETH_RSS_IP | RTE_ETH_RSS_TCP | > RTE_ETH_RSS_UDP; > + > + port_conf.rxmode.mq_mode =3D RTE_ETH_MQ_RX_RSS; > + port_conf.rx_adv_conf.rss_conf.rss_hf =3D rss_hf & > port_info.flow_type_rss_offloads; > + } > + > + numa_node =3D rte_eth_dev_socket_id(port_id); > + if (numa_node =3D=3D SOCKET_ID_ANY) > + numa_node =3D 0; > + > + if (params->mtu) > + port_conf.rxmode.mtu =3D params->mtu; > + > + rc =3D rte_eth_dev_configure(port_id, params->rx.n_queues, params->tx.n= _queues, > + &port_conf); > + if (rc < 0) > + return -EINVAL; > + > + rc =3D rte_eth_macaddr_get(port_id, &smac); > + if (rc < 0) > + return -EINVAL; > + > + printf("Port_id =3D %d srcmac =3D %x:%x:%x:%x:%x:%x\n", port_id, > + smac.addr_bytes[0], smac.addr_bytes[1], > + smac.addr_bytes[2], smac.addr_bytes[3], > + smac.addr_bytes[4], smac.addr_bytes[5]); > + > + /* Port RX */ > + for (i =3D 0; i < params->rx.n_queues; i++) { > + rc =3D rte_eth_rx_queue_setup(port_id, i, params->rx.queue_size, > numa_node, NULL, > + mempool); > + if (rc < 0) > + return -EINVAL; > + } > + > + /* Port TX */ > + for (i =3D 0; i < params->tx.n_queues; i++) { > + rc =3D rte_eth_tx_queue_setup(port_id, i, params->tx.queue_size, > numa_node, NULL); > + if (rc < 0) > + return -EINVAL; > + } > + > + memcpy(&port_list[port_id].config, params, sizeof(struct ethdev_config)= ); > + memcpy(port_list[port_id].config.dev_name, name, strlen(name)); > + port_list[port_id].config.port_id =3D port_id; > + enabled_port_mask |=3D RTE_BIT32(port_id); > + return 0; > +} > + > +static int > +cmd_ethdev_mtu(char **tokens, uint32_t n_tokens __rte_unused, char *out,= size_t > out_size, > + void *obj __rte_unused) > +{ > + int rc =3D -EINVAL; > + uint32_t mtu =3D 0; > + > + if (n_tokens !=3D 4) { > + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); > + return rc; > + } > + > + if (parser_uint32_read(&mtu, tokens[3]) !=3D 0) { > + snprintf(out, out_size, MSG_ARG_INVALID, "mtu_sz"); > + return rc; > + } > + > + rc =3D ethdev_mtu_config(tokens[1], mtu); > + if (rc < 0) > + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); > + > + return rc; > +} > + > +static int > +cmd_ethdev_prom_mode(char **tokens, uint32_t n_tokens __rte_unused, char= *out, > size_t out_size, > + void *obj __rte_unused) > +{ > + bool enable =3D false; > + int rc =3D -EINVAL; > + > + if (n_tokens !=3D 4) { > + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); > + return rc; > + } > + > + if (strcmp(tokens[3], "on") =3D=3D 0) > + enable =3D true; > + > + rc =3D ethdev_prom_mode_config(tokens[1], enable); > + if (rc < 0) > + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); > + > + return rc; > +} > + > +static int > +cmd_ip4_addr(char **tokens, uint32_t n_tokens, char *out, size_t out_siz= e, void *obj > __rte_unused) > +{ > + struct ipv4_addr_config config; > + int rc =3D -EINVAL; > + > + if (n_tokens !=3D 8) { > + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); > + goto exit; > + } > + > + if (strcmp(tokens[3], "addr")) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "addr"); > + goto exit; > + } > + > + if (strcmp(tokens[4], "add")) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); > + goto exit; > + } > + > + if (parser_ip4_read(&config.ip, tokens[5])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "ip"); > + goto exit; > + } > + > + if (strcmp(tokens[6], "netmask")) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "netmask"); > + goto exit; > + } > + > + if (parser_ip4_read(&config.mask, tokens[7])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "netmask"); > + goto exit; > + } > + > + rc =3D ethdev_ip4_addr_add(tokens[1], &config); > + if (rc < 0) > + snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); > + > +exit: > + return rc; > +} > + > +static int > +cmd_ip6_addr(char **tokens, uint32_t n_tokens, char *out, size_t out_siz= e, void *obj > __rte_unused) > +{ > + struct ipv6_addr_config config; > + int rc =3D -EINVAL; > + > + if (n_tokens !=3D 8) { > + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); > + goto exit; > + } > + > + if (strcmp(tokens[3], "addr")) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "addr"); > + goto exit; > + } > + > + if (strcmp(tokens[4], "add")) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); > + goto exit; > + } > + > + if (parser_ip6_read(config.ip, tokens[5])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "ip"); > + goto exit; > + } > + > + if (strcmp(tokens[6], "netmask")) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "netmask"); > + goto exit; > + } > + > + if (parser_ip6_read(config.mask, tokens[7])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "netmask"); > + goto exit; > + } > + > + rc =3D ethdev_ip6_addr_add(tokens[1], &config); > + if (rc < 0) > + snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); > + > +exit: > + return rc; > +} > + > +static int > +cmd_ethdev_show(char **tokens, uint32_t n_tokens, char *out, size_t out_= size, > + void *obj __rte_unused) > +{ > + int rc =3D -EINVAL; > + > + if (n_tokens !=3D 3) { > + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); > + return rc; > + } > + > + rc =3D ethdev_show(tokens[1], &out, &out_size); > + if (rc < 0) > + snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); > + > + return rc; > +} > + > +static int > +cmd_ethdev(char **tokens, uint32_t n_tokens, char *out, size_t out_size,= void *obj > __rte_unused) > +{ > + struct ethdev_config config; > + char *name; > + int rc; > + > + if (n_tokens < 7) { > + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); > + return -EINVAL; > + } > + > + memset(&config, 0, sizeof(struct ethdev_config)); > + name =3D tokens[1]; > + > + if (strcmp(tokens[2], "rxq") !=3D 0) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq"); > + return -EINVAL; > + } > + > + if (parser_uint32_read(&config.rx.n_queues, tokens[3]) !=3D 0) { > + snprintf(out, out_size, MSG_ARG_INVALID, "n_queues"); > + return -EINVAL; > + } > + > + if (strcmp(tokens[4], "txq") !=3D 0) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq"); > + return -EINVAL; > + } > + > + if (parser_uint32_read(&config.tx.n_queues, tokens[5]) !=3D 0) { > + snprintf(out, out_size, MSG_ARG_INVALID, "n_queues"); > + return -EINVAL; > + } > + > + mempcpy(config.rx.mempool_name, tokens[6], strlen(tokens[6])); > + > + if (n_tokens > 7) { > + if (strcmp(tokens[7], "mtu") !=3D 0) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu"); > + return -EINVAL; > + } > + > + if (parser_uint32_read(&config.mtu, tokens[8]) !=3D 0) { > + snprintf(out, out_size, MSG_ARG_INVALID, "mtu_sz"); > + return -EINVAL; > + } > + } > + > + config.tx.queue_size =3D ETHDEV_TX_DESC_DEFAULT; > + config.rx.queue_size =3D ETHDEV_RX_DESC_DEFAULT; > + > + rc =3D ethdev_process(name, &config); > + if (rc < 0) > + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); > + > + return rc; > +} > + > +static int > +cli_ethdev_help(char **tokens __rte_unused, uint32_t n_tokens __rte_unus= ed, char > *out, > + size_t out_size, void *obj __rte_unused) > +{ > + size_t len; > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "\n%s\n", > + "----------------------------- ethdev command help ------------------= -----------"); > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "%s\n", cmd_ethdev_help); > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "%s\n", cmd_ethdev_ip4_addr_help); > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "%s\n", cmd_ethdev_ip6_addr_help); > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "%s\n", cmd_ethdev_prom_mode_help); > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "%s\n", cmd_ethdev_mtu_help); > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "%s\n", cmd_ethdev_show_help); > + > + return 0; > +} > + > +static int > +cli_ethdev(char **tokens, uint32_t n_tokens, char *out, size_t out_size,= void *obj) > +{ > + if (strcmp(tokens[2], "show") =3D=3D 0) > + return cmd_ethdev_show(tokens, n_tokens, out, out_size, obj); > + else if (strcmp(tokens[2], "mtu") =3D=3D 0) > + return cmd_ethdev_mtu(tokens, n_tokens, out, out_size, obj); > + else if (strcmp(tokens[2], "promiscuous") =3D=3D 0) > + return cmd_ethdev_prom_mode(tokens, n_tokens, out, out_size, obj); > + else if (strcmp(tokens[2], "ip4") =3D=3D 0) > + return cmd_ip4_addr(tokens, n_tokens, out, out_size, obj); > + else if (strcmp(tokens[2], "ip6") =3D=3D 0) > + return cmd_ip6_addr(tokens, n_tokens, out, out_size, obj); > + else > + return cmd_ethdev(tokens, n_tokens, out, out_size, obj); > +} > + > +static struct cli_module ethdev =3D { > + .cmd =3D "ethdev", > + .process =3D cli_ethdev, > + .usage =3D cli_ethdev_help, > +}; > + > +CLI_REGISTER(ethdev); > diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h > new file mode 100644 > index 0000000000..9c3de49826 > --- /dev/null > +++ b/app/graph/ethdev.h > @@ -0,0 +1,28 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#ifndef APP_GRAPH_ETHDEV_H > +#define APP_GRAPH_ETHDEV_H > + > +#define ETHDEV_IPV6_ADDR_LEN 16 > + > +struct ipv4_addr_config { > + uint32_t ip; > + uint32_t mask; > +}; > + > +struct ipv6_addr_config { > + uint8_t ip[ETHDEV_IPV6_ADDR_LEN]; > + uint8_t mask[ETHDEV_IPV6_ADDR_LEN]; > +}; > + > +extern uint32_t enabled_port_mask; > + > +void ethdev_start(void); > +void ethdev_stop(void); > +void *ethdev_mempool_list_by_portid(uint16_t portid); > +int16_t ethdev_portid_by_ip4(uint32_t ip); > +int16_t ethdev_portid_by_ip6(uint8_t *ip); > + > +#endif > diff --git a/app/graph/ethdev_priv.h b/app/graph/ethdev_priv.h > new file mode 100644 > index 0000000000..1026c2e5b6 > --- /dev/null > +++ b/app/graph/ethdev_priv.h > @@ -0,0 +1,46 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#ifndef APP_GRAPH_ETHDEV_PRIV_H > +#define APP_GRAPH_ETHDEV_PRIV_H > + > +#include "ethdev.h" > + > +#define ETHDEV_RXQ_RSS_MAX 16 > +#define ETHDEV_RX_DESC_DEFAULT 1024 > +#define ETHDEV_TX_DESC_DEFAULT 1024 > + > +struct ethdev_rss_config { > + uint32_t queue_id[ETHDEV_RXQ_RSS_MAX]; > + uint32_t n_queues; > +}; > + > +struct ethdev_config { > + char dev_name[RTE_ETH_NAME_MAX_LEN]; > + uint16_t port_id; > + > + struct { > + uint32_t n_queues; > + uint32_t queue_size; > + char mempool_name[RTE_MEMPOOL_NAMESIZE]; > + struct rte_mempool *mp; > + struct ethdev_rss_config *rss; > + } rx; > + > + struct { > + uint32_t n_queues; > + uint32_t queue_size; > + } tx; > + > + int promiscuous; > + uint32_t mtu; > +}; > + > +struct ethdev { > + struct ethdev_config config; > + struct ipv4_addr_config ip4_addr; > + struct ipv6_addr_config ip6_addr; > +}; > + > +#endif > diff --git a/app/graph/ethdev_rx.c b/app/graph/ethdev_rx.c > new file mode 100644 > index 0000000000..d706d145c1 > --- /dev/null > +++ b/app/graph/ethdev_rx.c > @@ -0,0 +1,139 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#include > +#include > + > +#include > + > +#include "ethdev_rx_priv.h" > +#include "module_api.h" > + > +static const char > +cmd_ethdev_rx_help[] =3D "ethdev_rx map port queue = core > "; > + > +static struct lcore_params lcore_params_array[ETHDEV_RX_LCORE_PARAMS_MAX= ]; > +struct rte_node_ethdev_config ethdev_conf[RTE_MAX_ETHPORTS]; > +struct lcore_params *lcore_params =3D lcore_params_array; > +struct lcore_conf lcore_conf[RTE_MAX_LCORE]; > +uint16_t nb_lcore_params; > + > +static void > +rx_map_configure(uint8_t port_id, uint32_t queue, uint32_t core) > +{ > + uint8_t n_rx_queue; > + > + n_rx_queue =3D lcore_conf[core].n_rx_queue; > + lcore_conf[core].rx_queue_list[n_rx_queue].port_id =3D port_id; > + lcore_conf[core].rx_queue_list[n_rx_queue].queue_id =3D queue; > + lcore_conf[core].n_rx_queue++; > +} > + > +uint8_t > +ethdev_rx_num_rx_queues_get(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 > +ethdev_rx_map_add(char *name, uint32_t queue, uint32_t core) > +{ > + uint16_t port_id; > + int rc; > + > + if (nb_lcore_params >=3D ETHDEV_RX_LCORE_PARAMS_MAX) > + return -EINVAL; > + > + rc =3D rte_eth_dev_get_port_by_name(name, &port_id); > + if (rc) > + return -EINVAL; > + > + rx_map_configure(port_id, queue, core); > + > + lcore_params_array[nb_lcore_params].port_id =3D port_id; > + lcore_params_array[nb_lcore_params].queue_id =3D queue; > + lcore_params_array[nb_lcore_params].lcore_id =3D core; > + nb_lcore_params++; > + return 0; > +} > + > +static int > +cli_ethdev_rx_help(char **tokens __rte_unused, uint32_t n_tokens __rte_u= nused, char > *out, > + size_t out_size, void *obj __rte_unused) > +{ > + size_t len; > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "\n%s\n", > + "---------------------------- ethdev_rx command help ----------------= -----------"); > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "%s\n", cmd_ethdev_rx_help); > + return 0; > +} > + > +static int > +cli_ethdev_rx(char **tokens, uint32_t n_tokens, char *out, size_t out_si= ze, void *obj > __rte_unused) > +{ > + char name[RTE_ETH_NAME_MAX_LEN]; > + uint32_t core_id, queue; > + int rc =3D -EINVAL; > + > + if (n_tokens !=3D 8) { > + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); > + goto exit; > + } > + > + strcpy(name, tokens[3]); > + > + if (strcmp(tokens[4], "queue") !=3D 0) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq"); > + goto exit; > + } > + > + if (parser_uint32_read(&queue, tokens[5]) !=3D 0) { > + snprintf(out, out_size, MSG_ARG_INVALID, "queue"); > + goto exit; > + } > + > + if (strcmp(tokens[6], "core") !=3D 0) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "core_id"); > + goto exit; > + } > + > + if (parser_uint32_read(&core_id, tokens[7]) !=3D 0) { > + snprintf(out, out_size, MSG_ARG_INVALID, "queue"); > + goto exit; > + } > + > + rc =3D ethdev_rx_map_add(name, queue, core_id); > + if (rc < 0) > + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); > + > +exit: > + return rc; > +} > + > +static struct cli_module ethdev_rx =3D { > + .cmd =3D "ethdev_rx", > + .process =3D cli_ethdev_rx, > + .usage =3D cli_ethdev_rx_help, > +}; > + > +CLI_REGISTER(ethdev_rx); > diff --git a/app/graph/ethdev_rx.h b/app/graph/ethdev_rx.h > new file mode 100644 > index 0000000000..d2c18f545f > --- /dev/null > +++ b/app/graph/ethdev_rx.h > @@ -0,0 +1,32 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#ifndef APP_GRAPH_ETHDEV_RX_H > +#define APP_GRAPH_ETHDEV_RX_H > + > +#define ETHDEV_RX_LCORE_PARAMS_MAX 1024 > +#define ETHDEV_RX_QUEUE_PER_LCORE_MAX 16 > + > +struct lcore_rx_queue { > + uint16_t port_id; > + uint8_t queue_id; > + char node_name[RTE_NODE_NAMESIZE]; > +}; > + > +struct lcore_conf { > + uint16_t n_rx_queue; > + struct lcore_rx_queue rx_queue_list[ETHDEV_RX_QUEUE_PER_LCORE_MAX]; > + struct rte_graph *graph; > + char name[RTE_GRAPH_NAMESIZE]; > + rte_graph_t graph_id; > +} __rte_cache_aligned; > + > +uint8_t ethdev_rx_num_rx_queues_get(uint16_t port); > + > +extern struct rte_node_ethdev_config ethdev_conf[RTE_MAX_ETHPORTS]; > +extern struct lcore_conf lcore_conf[RTE_MAX_LCORE]; > +extern struct lcore_params *lcore_params; > +extern uint16_t nb_lcore_params; > + > +#endif > diff --git a/app/graph/ethdev_rx_priv.h b/app/graph/ethdev_rx_priv.h > new file mode 100644 > index 0000000000..d714f83739 > --- /dev/null > +++ b/app/graph/ethdev_rx_priv.h > @@ -0,0 +1,23 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#ifndef APP_GRAPH_ETHDEV_RX_PRIV_H > +#define APP_GRAPH_ETHDEV_RX_PRIV_H > + > +#include > + > +#include > +#include > + > +#define MAX_RX_QUEUE_PER_PORT 128 > +#define MAX_JUMBO_PKT_LEN 9600 > +#define NB_SOCKETS 8 > + > +struct lcore_params { > + uint16_t port_id; > + uint8_t queue_id; > + uint8_t lcore_id; > +} __rte_cache_aligned; > + > +#endif > diff --git a/app/graph/examples/l3fwd.cli b/app/graph/examples/l3fwd.cli > new file mode 100644 > index 0000000000..9986e1b73e > --- /dev/null > +++ b/app/graph/examples/l3fwd.cli > @@ -0,0 +1,87 @@ > +; SPDX-License-Identifier: BSD-3-Clause > +; Copyright(c) 2023 Marvell. > + > +; > +; Graph configuration for given usecase > +; > +graph l3fwd coremask ff model default > + > +; > +; Mempools to be attached with ethdev > +; > +mempool mempool0 size 8192 buffers 4000 cache 256 numa 0 > + > +; > +; DPDK devices and configuration. > +; > +; Note: Customize the parameters below to match your setup. > +; > +ethdev 0002:04:00.0 rxq 1 txq 8 mempool0 mtu 1500 > +ethdev 0002:05:00.0 rxq 1 txq 8 mempool0 mtu 1600 > +ethdev 0002:06:00.0 rxq 1 txq 8 mempool0 mtu 1500 > +ethdev 0002:07:00.0 rxq 1 txq 8 mempool0 mtu 1600 > +ethdev 0002:04:00.0 mtu 1700 > +ethdev 0002:05:00.0 promiscuous on > + > +; > +; IPv4 addresses assigned to DPDK devices > +; > +ethdev 0002:04:00.0 ip4 addr add 10.0.2.1 netmask 255.255.255.0 > +ethdev 0002:05:00.0 ip4 addr add 20.0.2.1 netmask 255.255.255.0 > +ethdev 0002:06:00.0 ip4 addr add 30.0.2.1 netmask 255.255.255.0 > +ethdev 0002:07:00.0 ip4 addr add 40.0.2.1 netmask 255.255.255.0 > + > +; > +; IPv6 addresses assigned to DPDK devices > +; > +ethdev 0002:04:00.0 ip6 addr add 52:20:DA:4F:68:70:52:20:DA:4F:68:70:52:= 20:DA:4A > netmask FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00 > +ethdev 0002:05:00.0 ip6 addr add 62:20:DA:4F:68:70:52:20:DA:4F:68:70:52:= 20:DA:4B > netmask FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00 > +ethdev 0002:06:00.0 ip6 addr add 72:20:DA:4F:68:70:52:20:DA:4F:68:70:52:= 20:DA:4C > netmask FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00 > +ethdev 0002:07:00.0 ip6 addr add 82:20:DA:4F:68:70:52:20:DA:4F:68:70:52:= 20:DA:4D > netmask FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00 > + > +; > +; IPv4 routes which are installed to ipv4_lookup node for LPM processing > +; > +ipv4_lookup route add ipv4 10.0.2.0 netmask 255.255.255.0 via 10.0.2.1 > +ipv4_lookup route add ipv4 20.0.2.0 netmask 255.255.255.0 via 20.0.2.1 > +ipv4_lookup route add ipv4 30.0.2.0 netmask 255.255.255.0 via 30.0.2.1 > +ipv4_lookup route add ipv4 40.0.2.0 netmask 255.255.255.0 via 40.0.2.1 > + > +; > +; IPv6 routes which are installed to ipv6_lookup node for LPM processing > +; > +ipv6_lookup route add ipv6 52:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:= 4A netmask > FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00 via > 52:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4A > +ipv6_lookup route add ipv6 62:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:= 4B netmask > FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00 via > 62:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4B > +ipv6_lookup route add ipv6 72:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:= 4C netmask > FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00 via > 72:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4C > +ipv6_lookup route add ipv6 82:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:= 4D netmask > FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00 via > 82:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4D > + > +; > +; Peer MAC and IPv4 address mapping > +; > +neigh add ipv4 10.0.2.2 52:20:DA:4F:68:70 > +neigh add ipv4 20.0.2.2 62:20:DA:4F:68:70 > +neigh add ipv4 30.0.2.2 72:20:DA:4F:68:70 > +neigh add ipv4 40.0.2.2 82:20:DA:4F:68:70 > + > +; > +; Peer MAC and IPv6 address mapping > +; > +neigh add ipv6 52:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4A 52:20:DA:= 4F:68:70 > +neigh add ipv6 62:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4B 62:20:DA:= 4F:68:70 > +neigh add ipv6 72:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4C 72:20:DA:= 4F:68:70 > +neigh add ipv6 82:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4D 82:20:DA:= 4F:68:70 > + > +; > +; Port-Queue-Core mapping for ethdev_rx node > +; > +ethdev_rx map port 0002:04:00.0 queue 0 core 1 > +ethdev_rx map port 0002:05:00.0 queue 0 core 2 > +ethdev_rx map port 0002:06:00.0 queue 0 core 3 > +ethdev_rx map port 0002:07:00.0 queue 0 core 4 > + > +; > +; Graph start command to create graph. > +; > +; Note: No more command should come after this. > +; > +graph start > diff --git a/app/graph/graph.c b/app/graph/graph.c > new file mode 100644 > index 0000000000..8c75574ecd > --- /dev/null > +++ b/app/graph/graph.c > @@ -0,0 +1,383 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#include > +#include > +#include > + > +#include > +#include > + > +#include "graph_priv.h" > +#include "module_api.h" > + > +#define RTE_LOGTYPE_APP_GRAPH RTE_LOGTYPE_USER1 > + > +static const char > +cmd_graph_help[] =3D "graph bsz tmo coremask " > + "model "; > + > +static const char * const supported_usecases[] =3D {"l3fwd"}; > +struct graph_config graph_config; > + > +/* Check the link rc of all ports in up to 9s, and print them finally */ > +static 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 */ > + char link_rc_text[RTE_ETH_LINK_MAX_STR_LEN]; > + uint8_t count, all_ports_up, print_flag =3D 0; > + struct rte_eth_link link; > + uint16_t portid; > + int rc; > + > + printf("\nChecking link rc"); > + 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)); > + rc =3D rte_eth_link_get_nowait(portid, &link); > + if (rc < 0) { > + all_ports_up =3D 0; > + if (print_flag =3D=3D 1) > + printf("Port %u link get failed: %s\n", > + portid, rte_strerror(-rc)); > + continue; > + } > + > + /* Print link rc if flag set */ > + if (print_flag =3D=3D 1) { > + rte_eth_link_to_str(link_rc_text, sizeof(link_rc_text), > + &link); > + printf("Port %d %s\n", portid, link_rc_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 rc, 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 bool > +parser_usecases_read(char *usecases) > +{ > + bool valid =3D false; > + uint32_t i, j =3D 0; > + char *token; > + > + token =3D strtok(usecases, ","); > + while (token !=3D NULL) { > + for (i =3D 0; i < RTE_DIM(supported_usecases); i++) { > + if (strcmp(supported_usecases[i], token) =3D=3D 0) { > + graph_config.usecases[j].enabled =3D true; > + strcpy(graph_config.usecases[j].name, token); > + valid =3D true; > + j++; > + break; > + } > + } > + token =3D strtok(NULL, ","); > + } > + > + return valid; > +} > + > +static uint64_t > +graph_worker_count_get(void) > +{ > + uint64_t nb_worker =3D 0; > + uint64_t coremask; > + > + coremask =3D graph_config.params.coremask; > + while (coremask) { > + if (coremask & 0x1) > + nb_worker++; > + > + coremask =3D (coremask >> 1); > + } > + > + return nb_worker; > +} > + > +static struct rte_node_ethdev_config * > +graph_rxtx_node_config_get(uint32_t *num_conf, uint32_t *num_graphs) > +{ > + uint32_t n_tx_queue, nb_conf =3D 0, lcore_id; > + uint16_t queueid, portid, nb_graphs =3D 0; > + uint8_t nb_rx_queue, queue; > + struct lcore_conf *qconf; > + > + n_tx_queue =3D graph_worker_count_get(); > + if (n_tx_queue > RTE_MAX_ETHPORTS) > + n_tx_queue =3D RTE_MAX_ETHPORTS; > + > + RTE_ETH_FOREACH_DEV(portid) { > + /* Skip ports that are not enabled */ > + if ((enabled_port_mask & (1 << portid)) =3D=3D 0) { > + printf("\nSkipping disabled port %d\n", portid); > + continue; > + } > + > + nb_rx_queue =3D ethdev_rx_num_rx_queues_get(portid); > + > + /* 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 n_tx_queue; > + ethdev_conf[nb_conf].mp =3D ethdev_mempool_list_by_portid(portid); > + ethdev_conf[nb_conf].mp_count =3D 1; /* Check with pools */ > + > + nb_conf++; > + } > + > + 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) { > + portid =3D qconf->rx_queue_list[queue].port_id; > + queueid =3D qconf->rx_queue_list[queue].queue_id; > + > + /* Add this queue node to its graph */ > + snprintf(qconf->rx_queue_list[queue].node_name, > RTE_NODE_NAMESIZE, > + "ethdev_rx-%u-%u", portid, queueid); > + } > + if (qconf->n_rx_queue) > + nb_graphs++; > + } > + > + printf("\n"); > + > + ethdev_start(); > + check_all_ports_link_status(enabled_port_mask); > + > + *num_conf =3D nb_conf; > + *num_graphs =3D nb_graphs; > + return ethdev_conf; > +} > + > +static int > +graph_start(void) > +{ > + struct rte_node_ethdev_config *conf; > + uint32_t nb_graphs =3D 0, nb_conf, i; > + > + conf =3D graph_rxtx_node_config_get(&nb_conf, &nb_graphs); > + for (i =3D 0; i < MAX_GRAPH_USECASES; i++) { > + if (!strcmp(graph_config.usecases[i].name, "l3fwd")) { > + if (graph_config.usecases[i].enabled) { > + usecase_l3fwd_configure(conf, nb_conf, nb_graphs); > + break; > + } > + } > + } > + return 0; > +} > + > +static int > +graph_config_add(char *usecases, struct graph_config *config) > +{ > + if (!parser_usecases_read(usecases)) > + return -EINVAL; > + > + graph_config.params.bsz =3D config->params.bsz; > + graph_config.params.tmo =3D config->params.tmo; > + graph_config.params.coremask =3D config->params.coremask; > + graph_config.model =3D config->model; > + > + return 0; > +} > + > +int > +graph_walk_start(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, APP_GRAPH, "Lcore %u has nothing to do\n", lcore_id); > + return 0; > + } > + > + RTE_LOG(INFO, APP_GRAPH, "Entering main loop on lcore %u, graph %s(%p)\= n", > lcore_id, > + qconf->name, graph); > + > + while (likely(!force_quit)) > + rte_graph_walk(graph); > + > + return 0; > +} > + > +void > +graph_stats_print(void) > +{ > + const char topLeft[] =3D {27, '[', '1', ';', '1', 'H', '\0'}; > + const char clr[] =3D {27, '[', '2', 'J', '\0'}; > + struct rte_graph_cluster_stats_param s_param; > + struct rte_graph_cluster_stats *stats; > + 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; > + > + stats =3D rte_graph_cluster_stats_create(&s_param); > + if (stats =3D=3D NULL) > + rte_exit(EXIT_FAILURE, "Unable to create stats object\n"); > + > + 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); > +} > + > +static void > +graph_config_process(char **tokens, uint32_t n_tokens, char *out, size_t= out_size, > + void *obj __rte_unused) > +{ > + uint32_t bsz =3D 32, tmo =3D 0, coremask =3D 0xf; > + struct graph_config config; > + int idx =3D 2, rc; > + uint8_t model; > + > + if (n_tokens < 4) { > + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); > + return; > + } > + > +next_arg: > + if (strcmp(tokens[idx], "model")) { > + if (strcmp(tokens[idx], "bsz") =3D=3D 0) { > + if (parser_uint32_read(&bsz, tokens[idx + 1])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "bsz"); > + return; > + } > + > + } else if (strcmp(tokens[idx], "tmo") =3D=3D 0) { > + if (parser_uint32_read(&tmo, tokens[idx + 1])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "tmo"); > + return; > + } > + } else if (strcmp(tokens[idx], "coremask") =3D=3D 0) { > + coremask =3D strtol(tokens[idx + 1], NULL, 16); > + if (coremask =3D=3D 0) { > + snprintf(out, out_size, MSG_ARG_INVALID, "tmo"); > + return; > + } > + } else { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "usecases > params"); > + return; > + } > + > + idx +=3D 2; > + goto next_arg; > + } else { > + if (strcmp(tokens[idx + 1], "default") =3D=3D 0) { > + model =3D GRAPH_MODEL_RTC; > + } else if (strcmp(tokens[idx + 1], "rtc") =3D=3D 0) { > + model =3D GRAPH_MODEL_RTC; > + } else if (strcmp(tokens[idx + 1], "mcd") =3D=3D 0) { > + model =3D GRAPH_MODEL_MCD; > + } else { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "model > arguments"); > + return; > + } > + } > + > + config.params.bsz =3D bsz; > + config.params.tmo =3D tmo; > + config.params.coremask =3D coremask; > + config.model =3D model; > + rc =3D graph_config_add(tokens[1], &config); > + if (rc < 0) > + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); > +} > + > +static int > +cli_graph_help(char **tokens __rte_unused, uint32_t n_tokens __rte_unuse= d, char > *out, > + size_t out_size, void *obj __rte_unused) > +{ > + size_t len; > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "\n%s\n", > + "----------------------------- graph command help -------------------= ----------"); > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "%s\n", cmd_graph_help); > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "%s\n", "graph start"); > + return 0; > +} > + > +static int > +cli_graph(char **tokens, uint32_t n_tokens, char *out, size_t out_size, = void *obj > __rte_unused) > +{ > + if (strcmp(tokens[1], "start") =3D=3D 0) > + graph_start(); > + else > + graph_config_process(tokens, n_tokens, out, out_size, obj); > + > + return 0; > +} > + > +static struct cli_module graph =3D { > + .cmd =3D "graph", > + .process =3D cli_graph, > + .usage =3D cli_graph_help, > +}; > + > +CLI_REGISTER(graph); > diff --git a/app/graph/graph.h b/app/graph/graph.h > new file mode 100644 > index 0000000000..126e967d75 > --- /dev/null > +++ b/app/graph/graph.h > @@ -0,0 +1,11 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#ifndef APP_GRAPH_H > +#define APP_GRAPH_H > + > +int graph_walk_start(void *conf); > +void graph_stats_print(void); > + > +#endif > diff --git a/app/graph/graph_priv.h b/app/graph/graph_priv.h > new file mode 100644 > index 0000000000..655a028fb2 > --- /dev/null > +++ b/app/graph/graph_priv.h > @@ -0,0 +1,32 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#ifndef APP_GRAPH_PRIV_H > +#define APP_GRAPH_PRIV_H > + > +#define MAX_GRAPH_USECASES 32 > + > +enum graph_model { > + GRAPH_MODEL_RTC =3D 0x01, > + GRAPH_MODEL_MCD =3D 0x02, > +}; > + > +struct usecases { > + char name[32]; > + bool enabled; > +}; > + > +struct usecase_params { > + uint64_t coremask; > + uint32_t bsz; > + uint32_t tmo; > +}; > + > +struct graph_config { > + struct usecases usecases[MAX_GRAPH_USECASES]; > + struct usecase_params params; > + enum graph_model model; > +}; > + > +#endif > diff --git a/app/graph/ip4_route.c b/app/graph/ip4_route.c > new file mode 100644 > index 0000000000..5aba5b38f2 > --- /dev/null > +++ b/app/graph/ip4_route.c > @@ -0,0 +1,146 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#include > +#include > +#include > + > +#include > + > +#include "module_api.h" > + > +static const char > +cmd_ipv4_lookup_help[] =3D "ipv4_lookup route add ipv4 netmask via "; > + > +struct ipv4_route_config route4[MAX_ROUTE_ENTRIES]; > + > +static uint8_t > +convert_netmask_to_depth(uint32_t netmask) > +{ > + uint8_t zerobits =3D 0; > + > + while ((netmask & 0x1) =3D=3D 0) { > + netmask =3D netmask >> 1; > + zerobits++; > + } > + > + return (32 - zerobits); > +} > + > +static int > +route_ip4_add(struct ipv4_route_config *route) > +{ > + int i; > + > + for (i =3D 0; i < MAX_ROUTE_ENTRIES; i++) { > + if (!route4[i].is_used) > + break; > + } > + > + if (i =3D=3D MAX_ROUTE_ENTRIES) > + return -ENOMEM; [Nithin] Change neigh and route database to dynamic linked list instead of = using static array. > + > + route4[i].ip =3D route->ip; > + route4[i].netmask =3D route->netmask; > + route4[i].via =3D route->via; > + route4[i].is_used =3D true; > + return 0; > +} > + > +int > +route_ip4_add_to_lookup(void) > +{ > + struct ipv4_route_config *route =3D NULL; > + int rc =3D -EINVAL; > + uint8_t depth; > + int portid, i; > + > + for (i =3D 0; i < MAX_ROUTE_ENTRIES; i++) { > + if (route4[i].is_used) > + route =3D &route4[i]; > + > + portid =3D ethdev_portid_by_ip4(route->via); > + if (portid < 0) { > + printf("Invalid portid found to install the route\n"); > + return rc; > + } > + > + depth =3D convert_netmask_to_depth(route->netmask); > + > + rc =3D rte_node_ip4_route_add(route->ip, depth, portid, > + RTE_NODE_IP4_LOOKUP_NEXT_REWRITE); > + if (rc < 0) > + return rc; > + } > + > + return 0; > +} > + > +static int > +cli_ipv4_lookup_help(char **tokens __rte_unused, uint32_t n_tokens __rte= _unused, > char *out, > + size_t out_size, void *obj __rte_unused) > +{ > + size_t len; > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "\n%s\n", > + "--------------------------- ipv4_lookup command help ---------------= ----------- > "); > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "%s\n", cmd_ipv4_lookup_help); > + return 0; > +} > + > +static int > +cli_ipv4_lookup(char **tokens, uint32_t n_tokens, char *out, size_t out_= size, > + void *obj __rte_unused) > +{ > + struct ipv4_route_config config; > + int rc =3D -EINVAL; > + > + if (n_tokens !=3D 9) { > + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); > + goto exit; > + } > + > + if (parser_ip4_read(&config.ip, tokens[4])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "ipv4"); > + goto exit; > + } > + > + if (strcmp(tokens[5], "netmask")) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "netmask"); > + goto exit; > + } > + > + if (parser_ip4_read(&config.netmask, tokens[6])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "netmask"); > + goto exit; > + } > + > + if (strcmp(tokens[7], "via")) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "via"); > + goto exit; > + } > + > + if (parser_ip4_read(&config.via, tokens[8])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "via ip"); > + goto exit; > + } > + > + rc =3D route_ip4_add(&config); > + if (rc < 0) > + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); > + > +exit: > + return rc; > +} > + > +static struct cli_module ipv4_lookup =3D { > + .cmd =3D "ipv4_lookup", > + .process =3D cli_ipv4_lookup, > + .usage =3D cli_ipv4_lookup_help, > +}; > + > +CLI_REGISTER(ipv4_lookup); > diff --git a/app/graph/ip6_route.c b/app/graph/ip6_route.c > new file mode 100644 > index 0000000000..2c5397f9d3 > --- /dev/null > +++ b/app/graph/ip6_route.c > @@ -0,0 +1,154 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#include > +#include > +#include > + > +#include > + > +#include "module_api.h" > + > +static const char > +cmd_ipv6_lookup_help[] =3D "ipv6_lookup route add ipv6 netmask via "; > + > +struct ipv6_route_config route6[MAX_ROUTE_ENTRIES]; > + > +static uint8_t > +convert_ip6_netmask_to_depth(uint8_t *netmask) > +{ > + uint8_t setbits =3D 0; > + uint8_t mask; > + int i; > + > + for (i =3D 0; i < ETHDEV_IPV6_ADDR_LEN; i++) { > + mask =3D netmask[i]; > + while (mask & 0x80) { > + mask =3D mask << 1; > + setbits++; > + } > + } > + > + return setbits; > +} > + > +static int > +route_ip6_add(struct ipv6_route_config *route) > +{ > + int i, j; > + > + for (i =3D 0; i < RTE_MAX_ETHPORTS; i++) { > + if (!route6[i].is_used) > + break; > + } > + > + if (i =3D=3D RTE_MAX_ETHPORTS) > + return -ENOMEM; > + > + for (j =3D 0; j < ETHDEV_IPV6_ADDR_LEN; j++) { > + route6[i].ip[j] =3D route->ip[j]; > + route6[i].mask[j] =3D route->mask[j]; > + route6[i].gateway[j] =3D route->gateway[j]; > + } > + route6[i].is_used =3D true; > + > + return 0; > +} > + > +int > +route_ip6_add_to_lookup(void) > +{ > + struct ipv6_route_config *route =3D NULL; > + int rc =3D -EINVAL; > + uint8_t depth; > + int portid, i; > + > + for (i =3D 0; i < MAX_ROUTE_ENTRIES; i++) { > + if (route6[i].is_used) > + route =3D &route6[i]; > + > + portid =3D ethdev_portid_by_ip6(route->gateway); > + if (portid < 0) { > + printf("Invalid portid found to install the route\n"); > + return rc; > + } > + > + depth =3D convert_ip6_netmask_to_depth(route->mask); > + > + rc =3D rte_node_ip6_route_add(route->ip, depth, portid, > + RTE_NODE_IP6_LOOKUP_NEXT_REWRITE); > + if (rc < 0) > + return rc; > + } > + > + return 0; > +} > + > +static int > +cli_ipv6_lookup_help(char **tokens __rte_unused, uint32_t n_tokens __rte= _unused, > char *out, > + size_t out_size, void *obj __rte_unused) > +{ > + size_t len; > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "\n%s\n", > + "--------------------------- ipv6_lookup command help ---------------= ----------- > "); > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "%s\n", cmd_ipv6_lookup_help); > + return 0; > +} > + > +static int > +cli_ipv6_lookup(char **tokens, uint32_t n_tokens, char *out, size_t out_= size, > + void *obj __rte_unused) > +{ > + struct ipv6_route_config config; > + int rc =3D -EINVAL; > + > + if (n_tokens !=3D 9) { > + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); > + goto exit; > + } > + > + if (parser_ip6_read(config.ip, tokens[4])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "ipv6"); > + goto exit; > + } > + > + if (strcmp(tokens[5], "netmask")) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "netmask"); > + goto exit; > + } > + > + if (parser_ip6_read(config.mask, tokens[6])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "netmask"); > + goto exit; > + } > + > + if (strcmp(tokens[7], "via")) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "via"); > + goto exit; > + } > + > + if (parser_ip6_read(config.gateway, tokens[8])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "gateway ip"); > + goto exit; > + } > + > + rc =3D route_ip6_add(&config); > + if (rc) > + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); > + > +exit: > + return rc; > +} > + > +static struct cli_module ipv6_lookup =3D { > + .cmd =3D "ipv6_lookup", > + .process =3D cli_ipv6_lookup, > + .usage =3D cli_ipv6_lookup_help, > +}; > + > +CLI_REGISTER(ipv6_lookup); > diff --git a/app/graph/l3fwd.c b/app/graph/l3fwd.c > new file mode 100644 > index 0000000000..85b8b2618e > --- /dev/null > +++ b/app/graph/l3fwd.c > @@ -0,0 +1,152 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "module_api.h" > + > +static char pcap_filename[RTE_GRAPH_PCAP_FILE_SZ]; > +static uint64_t packet_to_capture; > +static int pcap_trace_enable; > + > +static int > +l3fwd_pattern_configure(void) > +{ > + /* Graph initialization. 8< */ > + static const char * const default_patterns[] =3D { > + "ip4*", > + "ethdev_tx-*", > + "pkt_drop", > + }; > + > + struct rte_graph_param graph_conf; > + const char **node_patterns; > + struct lcore_conf *qconf; > + uint16_t nb_patterns; > + uint8_t lcore_id; > + int rc; > + > + nb_patterns =3D RTE_DIM(default_patterns); > + node_patterns =3D malloc((ETHDEV_RX_QUEUE_PER_LCORE_MAX + nb_patterns) = * > + sizeof(*node_patterns)); > + if (!node_patterns) > + return -ENOMEM; > + memcpy(node_patterns, default_patterns, > + nb_patterns * sizeof(*node_patterns)); > + > + memset(&graph_conf, 0, sizeof(graph_conf)); > + graph_conf.node_patterns =3D node_patterns; > + > + /* Pcap config */ > + graph_conf.pcap_enable =3D pcap_trace_enable; > + graph_conf.num_pkt_to_capture =3D packet_to_capture; > + graph_conf.pcap_filename =3D pcap_filename; > + > + 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; > + > + /* Add rx node patterns of this lcore */ > + for (i =3D 0; i < qconf->n_rx_queue; i++) { > + graph_conf.node_patterns[nb_patterns + i] =3D > + qconf->rx_queue_list[i].node_name; > + } > + > + graph_conf.nb_node_patterns =3D nb_patterns + i; > + 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); > + /* >8 End of graph initialization. */ > + if (!qconf->graph) > + rte_exit(EXIT_FAILURE, > + "rte_graph_lookup(): graph %s not found\n", > + qconf->name); > + } > + > + rc =3D route_ip4_add_to_lookup(); > + if (rc < 0) > + rte_exit(EXIT_FAILURE, "Unable to add v4 route to lookup table\n"); > + > + rc =3D route_ip6_add_to_lookup(); > + if (rc < 0) > + rte_exit(EXIT_FAILURE, "Unable to add v6 route to lookup table\n"); > + > + rc =3D neigh_ip4_add_to_rewrite(); > + if (rc < 0) > + rte_exit(EXIT_FAILURE, "Unable to add v4 to rewrite node\n"); > + > + rc =3D neigh_ip6_add_to_rewrite(); > + if (rc < 0) > + rte_exit(EXIT_FAILURE, "Unable to add v6 to rewrite node\n"); > + > + /* Launch per-lcore init on every worker lcore */ > + rte_eal_mp_remote_launch(graph_walk_start, NULL, SKIP_MAIN); > + > + /* Accumulate and print stats on main until exit */ > + if (rte_graph_has_stats_feature() && app_graph_stats_enabled()) > + graph_stats_print(); > + > + /* Wait for worker cores to exit */ > + rc =3D 0; > + RTE_LCORE_FOREACH_WORKER(lcore_id) { > + rc =3D rte_eal_wait_lcore(lcore_id); > + /* Destroy graph */ > + if (rc < 0 || > + rte_graph_destroy(rte_graph_from_name(lcore_conf[lcore_id].name))) > { > + rc =3D -1; > + break; > + } > + } > + free(node_patterns); > + > + ethdev_stop(); > + return rc; > +} > + > +int > +usecase_l3fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb= _confs, > uint16_t nb_graphs) > +{ > + int rc; > + > + rc =3D rte_node_eth_config(conf, nb_confs, nb_graphs); > + if (rc) > + rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=3D%d\n", rc); > + > + rc =3D l3fwd_pattern_configure(); > + if (rc) > + rte_exit(EXIT_FAILURE, "l3fwd_pattern_failure: err=3D%d\n", rc); > + > + return rc; > +} > diff --git a/app/graph/l3fwd.h b/app/graph/l3fwd.h > new file mode 100644 > index 0000000000..e1d23165e6 > --- /dev/null > +++ b/app/graph/l3fwd.h > @@ -0,0 +1,11 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#ifndef APP_GRAPH_L3FWD_H > +#define APP_GRAPH_L3FWD_H > + > +int usecase_l3fwd_configure(struct rte_node_ethdev_config *conf, uint16_= t nb_conf, > + uint16_t nb_graphs); > + > +#endif > diff --git a/app/graph/main.c b/app/graph/main.c > new file mode 100644 > index 0000000000..e9934025bf > --- /dev/null > +++ b/app/graph/main.c > @@ -0,0 +1,201 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > + > +#include "module_api.h" > + > +volatile bool force_quit; > + > +static const char usage[] =3D "%s EAL_ARGS -- -s SCRIPT [-h HOST] [-p PO= RT] [--enable-graph- > stats] " > + "[--help]\n"; > + > +static struct app_params { > + struct conn_params conn; > + char *script_name; > + bool enable_graph_stats; > +} app =3D { > + .conn =3D { > + .welcome =3D "\nWelcome!\n\n", > + .prompt =3D "graph> ", > + .addr =3D "0.0.0.0", > + .port =3D 8086, > + .buf_size =3D 1024 * 1024, > + .msg_in_len_max =3D 1024, > + .msg_out_len_max =3D 1024 * 1024, > + .msg_handle =3D cli_process, > + .msg_handle_arg =3D NULL, /* set later. */ > + }, > + .script_name =3D NULL, > + .enable_graph_stats =3D false, > +}; > + > +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; > + } > +} > + > +static int > +app_args_parse(int argc, char **argv) > +{ > + struct option lgopts[] =3D { > + {"help", 0, 0, 'H'}, > + {"enable-graph-stats", 0, 0, 'g'}, > + }; > + int h_present, p_present, s_present, n_args, i; > + char *app_name =3D argv[0]; > + int opt, option_index; > + > + /* Skip EAL input args */ > + n_args =3D argc; > + for (i =3D 0; i < n_args; i++) > + if (strcmp(argv[i], "--") =3D=3D 0) { > + argc -=3D i; > + argv +=3D i; > + break; > + } > + > + if (i =3D=3D n_args) > + return 0; > + > + /* Parse args */ > + h_present =3D 0; > + p_present =3D 0; > + s_present =3D 0; > + > + while ((opt =3D getopt_long(argc, argv, "h:p:s:", lgopts, &option_index= )) !=3D EOF) { > + switch (opt) { > + case 'h': > + if (h_present) { > + printf("Error: Multiple -h arguments\n"); > + return -1; > + } > + h_present =3D 1; > + > + if (!strlen(optarg)) { > + printf("Error: Argument for -h not provided\n"); > + return -1; > + } > + > + app.conn.addr =3D strdup(optarg); > + if (app.conn.addr =3D=3D NULL) { > + printf("Error: Not enough memory\n"); > + return -1; > + } > + break; > + > + case 'p': > + if (p_present) { > + printf("Error: Multiple -p arguments\n"); > + return -1; > + } > + p_present =3D 1; > + > + if (!strlen(optarg)) { > + printf("Error: Argument for -p not provided\n"); > + return -1; > + } > + > + app.conn.port =3D (uint16_t) atoi(optarg); > + break; > + > + case 's': > + if (s_present) { > + printf("Error: Multiple -s arguments\n"); > + return -1; > + } > + s_present =3D 1; > + > + if (!strlen(optarg)) { > + printf("Error: Argument for -s not provided\n"); > + return -1; > + } > + > + app.script_name =3D strdup(optarg); > + if (app.script_name =3D=3D NULL) { > + printf("Error: Not enough memory\n"); > + return -1; > + } > + break; > + > + case 'g': > + app.enable_graph_stats =3D true; > + break; > + > + case 'H': > + default: > + printf(usage, app_name); > + return -1; > + } > + } > + optind =3D 1; /* reset getopt lib */ > + > + return 0; > +} > + > +bool > +app_graph_stats_enabled(void) > +{ > + return app.enable_graph_stats; > +} > + > +int > +main(int argc, char **argv) > +{ > + struct conn *conn; > + int rc; > + > + /* Parse application arguments */ > + rc =3D app_args_parse(argc, argv); > + if (rc < 0) > + return rc; > + > + /* EAL */ > + rc =3D rte_eal_init(argc, argv); > + if (rc < 0) { > + printf("Error: EAL initialization failed (%d)\n", rc); > + return rc; > + }; > + > + force_quit =3D false; > + signal(SIGINT, signal_handler); > + signal(SIGTERM, signal_handler); > + > + /* Script */ > + if (app.script_name) { > + cli_script_process(app.script_name, app.conn.msg_in_len_max, > + app.conn.msg_out_len_max, NULL); > + } > + > + /* Connectivity */ > + app.conn.msg_handle_arg =3D NULL; > + conn =3D conn_init(&app.conn); > + if (!conn) { > + printf("Error: Connectivity initialization failed (%d)\n", rc); > + return rc; > + }; > + > + /* Dispatch loop */ > + while (1) { > + conn_req_poll(conn); > + > + conn_msg_poll(conn); > + } > + > + /* clean up the EAL */ > + rte_eal_cleanup(); > +} > diff --git a/app/graph/mempool.c b/app/graph/mempool.c > new file mode 100644 > index 0000000000..1cee66abed > --- /dev/null > +++ b/app/graph/mempool.c > @@ -0,0 +1,134 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#include > +#include > +#include > + > +#include > +#include > + > +#include "mempool_priv.h" > +#include "module_api.h" > + > +static const char > +cmd_mempool_help[] =3D "mempool size buffers > " > + "cache numa "; > + > +struct mempools mpconfig; > + > +int > +mempool_process(struct mempool_config *config) > +{ > + struct rte_mempool *mp; > + uint8_t nb_pools; > + > + nb_pools =3D mpconfig.nb_pools; > + strcpy(mpconfig.config[nb_pools].name, config->name); > + mpconfig.config[nb_pools].pool_size =3D config->pool_size; > + mpconfig.config[nb_pools].buffer_size =3D config->buffer_size; > + mpconfig.config[nb_pools].cache_size =3D config->cache_size; > + mpconfig.config[nb_pools].numa_node =3D config->numa_node; > + > + mp =3D rte_pktmbuf_pool_create(config->name, config->pool_size, config- > >cache_size, > + 64, config->buffer_size, config->numa_node); > + if (!mp) > + return -EINVAL; > + > + mpconfig.mp[nb_pools] =3D mp; > + nb_pools++; > + mpconfig.nb_pools =3D nb_pools; > + > + return 0; > +} > + > +static int > +cli_mempool_help(char **tokens __rte_unused, uint32_t n_tokens __rte_unu= sed, char > *out, > + size_t out_size, void *obj __rte_unused) > +{ > + size_t len; > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "\n%s\n", > + "---------------------------- mempool command help ------------------= ----------"); > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "%s\n", cmd_mempool_help); > + return 0; > +} > + > +static int > +cli_mempool(char **tokens, uint32_t n_tokens, char *out, size_t out_size= , void *obj > __rte_unused) > +{ > + uint32_t pkt_buffer_size, pool_size, cache_size, numa_node; > + struct mempool_config config; > + int rc =3D -EINVAL; > + > + if (n_tokens !=3D 10) { > + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); > + goto exit; > + } > + > + if (strcmp(tokens[2], "size")) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); > + goto exit; > + } > + > + if (parser_uint32_read(&pkt_buffer_size, tokens[3])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "mbuf_size"); > + goto exit; > + } > + > + if (strcmp(tokens[4], "buffers")) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffers"); > + goto exit; > + } > + > + if (parser_uint32_read(&pool_size, tokens[5])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "number_of_buffers"); > + goto exit; > + } > + > + if (strcmp(tokens[6], "cache")) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache"); > + goto exit; > + } > + > + if (parser_uint32_read(&cache_size, tokens[7])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "cache_size"); > + goto exit; > + } > + > + if (strcmp(tokens[8], "numa")) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "numa"); > + goto exit; > + } > + > + if (parser_uint32_read(&numa_node, tokens[9])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "numa_id"); > + goto exit; > + } > + > + strcpy(config.name, tokens[1]); > + config.name[strlen(tokens[1])] =3D '\0'; > + config.pool_size =3D pool_size; > + config.buffer_size =3D pkt_buffer_size; > + config.cache_size =3D cache_size; > + config.numa_node =3D numa_node; > + > + rc =3D mempool_process(&config); > + if (rc < 0) > + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); > + > +exit: > + return rc; > +} > + > +static struct cli_module mempool =3D { > + .cmd =3D "mempool", > + .process =3D cli_mempool, > + .usage =3D cli_mempool_help, > +}; > + > +CLI_REGISTER(mempool); > diff --git a/app/graph/mempool.h b/app/graph/mempool.h > new file mode 100644 > index 0000000000..5fc788199d > --- /dev/null > +++ b/app/graph/mempool.h > @@ -0,0 +1,18 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#ifndef APP_GRAPH_MEMPOOL_H > +#define APP_GRAPH_MEMPOOL_H > + > +struct mempool_config { > + char name[RTE_MEMPOOL_NAMESIZE]; > + int pool_size; > + int cache_size; > + int buffer_size; > + int numa_node; > +}; > + > +int mempool_process(struct mempool_config *config); > + > +#endif > diff --git a/app/graph/mempool_priv.h b/app/graph/mempool_priv.h > new file mode 100644 > index 0000000000..5a55722b32 > --- /dev/null > +++ b/app/graph/mempool_priv.h > @@ -0,0 +1,16 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#ifndef APP_GRAPH_MEMPOOL_PRIV_H > +#define APP_GRAPH_MEMPOOL_PRIV_H > + > +#include "mempool.h" > + > +struct mempools { > + struct mempool_config config[RTE_MAX_ETHPORTS]; > + struct rte_mempool *mp[RTE_MAX_ETHPORTS]; > + uint8_t nb_pools; > +}; > + > +#endif > diff --git a/app/graph/meson.build b/app/graph/meson.build > new file mode 100644 > index 0000000000..a3011e504b > --- /dev/null > +++ b/app/graph/meson.build > @@ -0,0 +1,25 @@ > +# SPDX-License-Identifier: BSD-3-Clause > +# Copyright(c) 2023 Marvell. > + > +# override default name to drop the hyphen > +name =3D 'graph' > +build =3D cc.has_header('sys/epoll.h') > +if not build > + subdir_done() > +endif > + > +deps +=3D ['bus_pci', 'graph', 'eal', 'lpm', 'ethdev', 'node'] > +sources =3D files( > + 'cli.c', > + 'conn.c', > + 'ethdev_rx.c', > + 'ethdev.c', > + 'graph.c', > + 'ip4_route.c', > + 'ip6_route.c', > + 'main.c', > + 'mempool.c', > + 'neigh.c', > + 'l3fwd.c', > + 'utils.c', > +) > diff --git a/app/graph/module_api.h b/app/graph/module_api.h > new file mode 100644 > index 0000000000..09b10bc672 > --- /dev/null > +++ b/app/graph/module_api.h > @@ -0,0 +1,33 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#ifndef APP_GRAPH_MODULE_API_H > +#define APP_GRAPH_MODULE_API_H > + > +#include > + > +#include > +#include > +#include > +#include > + > +#include "conn.h" > +#include "cli.h" > +#include "ethdev.h" > +#include "ethdev_rx.h" > +#include "graph.h" > +#include "l3fwd.h" > +#include "mempool.h" > +#include "neigh.h" > +#include "route.h" > +#include "utils.h" > + > +/* > + * Externs > + */ > +extern volatile bool force_quit; > + > +bool app_graph_stats_enabled(void); > + > +#endif > diff --git a/app/graph/neigh.c b/app/graph/neigh.c > new file mode 100644 > index 0000000000..07766758c9 > --- /dev/null > +++ b/app/graph/neigh.c > @@ -0,0 +1,269 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#include > +#include > +#include > +#include > + > +#include > +#include > + > +#include "neigh_priv.h" > +#include "module_api.h" > + > +static const char > +cmd_neigh_v4_help[] =3D "neigh add ipv4 "; > + > +static const char > +cmd_neigh_v6_help[] =3D "neigh add ipv6 "; > + > +struct ipv4_neigh_config neigh4[MAX_NEIGH_ENTRIES]; > +struct ipv6_neigh_config neigh6[MAX_NEIGH_ENTRIES]; > + > +static int > +neigh_ip4_add(uint32_t ip, uint64_t mac) > +{ > + int i; > + > + for (i =3D 0; i < MAX_NEIGH_ENTRIES; i++) { > + if (!neigh4[i].is_used) > + break; > + } > + > + if (i =3D=3D MAX_NEIGH_ENTRIES) > + return -ENOMEM; > + > + neigh4[i].ip =3D ip; > + neigh4[i].mac =3D mac; > + neigh4[i].is_used =3D true; > + return 0; > +} > + > +static int > +neigh_ip6_add(uint8_t *ip, uint64_t mac) > +{ > + int i, j; > + > + for (i =3D 0; i < MAX_NEIGH_ENTRIES; i++) { > + if (!neigh6[i].is_used) > + break; > + } > + > + if (i =3D=3D MAX_NEIGH_ENTRIES) > + return -ENOMEM; > + > + for (j =3D 0; j < ETHDEV_IPV6_ADDR_LEN; j++) > + neigh6[i].ip[j] =3D ip[j]; > + > + neigh6[i].mac =3D mac; > + neigh6[i].is_used =3D true; > + return 0; > +} > + > +int > +neigh_ip4_add_to_rewrite(void) > +{ > + uint8_t data[2 * RTE_ETHER_ADDR_LEN]; > + uint8_t len =3D 2 * RTE_ETHER_ADDR_LEN; > + struct rte_ether_addr smac =3D {0}; > + struct ipv4_neigh_config *neigh; > + int16_t portid =3D 0; > + int rc, i; > + > + for (i =3D 0; i < MAX_NEIGH_ENTRIES; i++) { > + if (!neigh4[i].is_used) > + continue; > + > + neigh =3D &neigh4[i]; > + portid =3D ethdev_portid_by_ip4(neigh->ip); > + if (portid < 0) { > + printf("Invalid portid found to add neigh\n"); > + return -EINVAL; > + } > + > + memset(data, 0, len); > + > + /* Copy dst mac */ > + rte_memcpy((void *)&data[0], (void *)&neigh->mac, > RTE_ETHER_ADDR_LEN); > + > + /* Copy src mac */ > + rc =3D rte_eth_macaddr_get(portid, &smac); > + if (rc < 0) { > + printf("Cannot get MAC address: err=3D%d, port=3D%d\n", rc, portid); > + return rc; > + } > + > + rte_memcpy(&data[RTE_ETHER_ADDR_LEN], smac.addr_bytes, > RTE_ETHER_ADDR_LEN); > + > + rc =3D rte_node_ip4_rewrite_add(portid, data, len, portid); > + if (rc < 0) { > + printf("Error in writing rewrite data: err=3D%d, port=3D%d\n", rc, po= rtid); > + return rc; > + } > + } > + > + return 0; > +} > + > +int > +neigh_ip6_add_to_rewrite(void) > +{ > + uint8_t data[2 * RTE_ETHER_ADDR_LEN]; > + uint8_t len =3D 2 * RTE_ETHER_ADDR_LEN; > + struct rte_ether_addr smac =3D {0}; > + struct ipv6_neigh_config *neigh; > + int16_t portid =3D 0; > + int rc, i; > + > + for (i =3D 0; i < MAX_NEIGH_ENTRIES; i++) { > + if (!neigh6[i].is_used) > + continue; > + > + neigh =3D &neigh6[i]; > + portid =3D ethdev_portid_by_ip6(neigh->ip); > + if (portid < 0) { > + printf("Invalid portid found to add neigh\n"); > + return -EINVAL; > + } > + > + memset(data, 0, len); > + > + /* Copy dst mac */ > + rte_memcpy((void *)&data[0], (void *)&neigh->mac, > RTE_ETHER_ADDR_LEN); > + > + /* Copy src mac */ > + rc =3D rte_eth_macaddr_get(portid, &smac); > + if (rc < 0) { > + printf("Cannot get MAC address: err=3D%d, port=3D%d\n", > + rc, portid); > + return rc; > + } > + > + rte_memcpy(&data[RTE_ETHER_ADDR_LEN], smac.addr_bytes, > RTE_ETHER_ADDR_LEN); > + > + rc =3D rte_node_ip6_rewrite_add(portid, data, len, portid); > + if (rc < 0) { > + printf("Error in writing rewrite data: err=3D%d, port=3D%d\n", rc, po= rtid); > + return rc; > + } > + } > + > + return 0; > +} > + > +static int > +cmd_neigh_v4(char **tokens, uint32_t n_tokens, char *out, size_t out_siz= e, void *obj > __rte_unused) > +{ > + int rc =3D -EINVAL; > + uint64_t mac; > + uint32_t ip; > + > + if (n_tokens !=3D 5) { > + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); > + goto exit; > + } > + > + if (strcmp(tokens[1], "add")) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); > + goto exit; > + } > + > + if (strcmp(tokens[2], "ipv4")) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ipv4"); > + goto exit; > + } > + > + if (parser_ip4_read(&ip, tokens[3])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "ip"); > + goto exit; > + } > + > + if (parser_mac_read(&mac, tokens[4])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "mac"); > + goto exit; > + } > + > + rc =3D neigh_ip4_add(ip, mac); > + if (rc < 0) > + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); > + > +exit: > + return rc; > +} > + > +static int > +cmd_neigh_v6(char **tokens, uint32_t n_tokens, char *out, size_t out_siz= e, void *obj > __rte_unused) > +{ > + uint8_t ip[ETHDEV_IPV6_ADDR_LEN]; > + int rc =3D -EINVAL; > + uint64_t mac; > + > + if (n_tokens !=3D 5) { > + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); > + goto exit; > + } > + > + if (strcmp(tokens[1], "add")) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); > + goto exit; > + } > + > + if (strcmp(tokens[2], "ipv6")) { > + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ipv6"); > + goto exit; > + } > + > + if (parser_ip6_read(ip, tokens[3])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "ip"); > + goto exit; > + } > + > + if (parser_mac_read(&mac, tokens[4])) { > + snprintf(out, out_size, MSG_ARG_INVALID, "mac"); > + goto exit; > + } > + > + rc =3D neigh_ip6_add(ip, mac); > + if (rc < 0) > + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); > + > +exit: > + return rc; > +} > + > +static int > +cli_neigh_help(char **tokens __rte_unused, uint32_t n_tokens __rte_unuse= d, char *out, > + size_t out_size, void *obj __rte_unused) > +{ > + size_t len; > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "\n%s\n", > + "----------------------------- neigh command help -------------------= ----------"); > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "%s\n", cmd_neigh_v4_help); > + > + len =3D strlen(out); > + snprintf(out + len, out_size, "%s\n", cmd_neigh_v6_help); > + return 0; > +} > + > +static int > +cli_neigh(char **tokens, uint32_t n_tokens, char *out, size_t out_size, = void *obj) > +{ > + if (strcmp(tokens[2], "ipv4") =3D=3D 0) > + return cmd_neigh_v4(tokens, n_tokens, out, out_size, obj); > + else > + return cmd_neigh_v6(tokens, n_tokens, out, out_size, obj); > +} > + > +static struct cli_module neigh =3D { > + .cmd =3D "neigh", > + .process =3D cli_neigh, > + .usage =3D cli_neigh_help, > +}; > + > +CLI_REGISTER(neigh); [Nithin] Move logic for tokenizing into cmdline library itself. Module shou= ld only register the commands to libcmdline. > diff --git a/app/graph/neigh.h b/app/graph/neigh.h > new file mode 100644 > index 0000000000..3964c37bb0 > --- /dev/null > +++ b/app/graph/neigh.h > @@ -0,0 +1,11 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#ifndef APP_GRAPH_NEIGH_H > +#define APP_GRAPH_NEIGH_H > + > +int neigh_ip4_add_to_rewrite(void); > +int neigh_ip6_add_to_rewrite(void); > + > +#endif > diff --git a/app/graph/neigh_priv.h b/app/graph/neigh_priv.h > new file mode 100644 > index 0000000000..745dc7d671 > --- /dev/null > +++ b/app/graph/neigh_priv.h > @@ -0,0 +1,22 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#ifndef APP_GRAPH_NEIGH_PRIV_H > +#define APP_GRAPH_NEIGH_PRIV_H > + > +#define MAX_NEIGH_ENTRIES 32 > + > +struct ipv4_neigh_config { > + uint32_t ip; > + uint64_t mac; > + bool is_used; > +}; > + > +struct ipv6_neigh_config { > + uint8_t ip[16]; > + uint64_t mac; > + bool is_used; > +}; > + > +#endif > diff --git a/app/graph/route.h b/app/graph/route.h > new file mode 100644 > index 0000000000..6b4acf3344 > --- /dev/null > +++ b/app/graph/route.h > @@ -0,0 +1,30 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#ifndef APP_GRAPH_ROUTE_H > +#define APP_GRAPH_ROUTE_H > + > +#define MAX_ROUTE_ENTRIES 32 > + > +struct ipv4_route_config { > + uint32_t ip; > + uint32_t netmask; > + uint32_t via; > + bool is_used; > +}; > + > +struct ipv6_route_config { > + uint8_t ip[16]; > + uint8_t mask[16]; > + uint8_t gateway[16]; > + bool is_used; > +}; > + > +extern struct ipv4_route_config route4[MAX_ROUTE_ENTRIES]; > +extern struct ipv6_route_config route6[MAX_ROUTE_ENTRIES]; > + > +int route_ip4_add_to_lookup(void); > +int route_ip6_add_to_lookup(void); > + > +#endif > diff --git a/app/graph/utils.c b/app/graph/utils.c > new file mode 100644 > index 0000000000..48a83e738c > --- /dev/null > +++ b/app/graph/utils.c > @@ -0,0 +1,155 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#include > +#include > +#include > +#include > + > +#include > + > +#include "module_api.h" > + > +#define white_spaces_skip(pos) \ > +({ \ > + __typeof__(pos) _p =3D (pos); \ > + for ( ; isspace(*_p); _p++) \ > + ; \ > + _p; \ > +}) > + > +static void > +hex_string_to_uint64(uint64_t *dst, const char *hexs) > +{ > + char buf[2] =3D {0}; > + uint8_t shift =3D 4; > + int iter =3D 0; > + char c; > + > + while ((c =3D *hexs++)) { > + buf[0] =3D c; > + *dst |=3D (strtol(buf, NULL, 16) << shift); > + shift -=3D 4; > + iter++; > + if (iter =3D=3D 2) { > + iter =3D 0; > + shift =3D 4; > + dst++; > + } > + } > +} > + > +int > +parser_uint64_read(uint64_t *value, const char *p) > +{ > + char *next; > + uint64_t val; > + > + p =3D white_spaces_skip(p); > + if (!isdigit(*p)) > + return -EINVAL; > + > + val =3D strtoul(p, &next, 0); > + if (p =3D=3D next) > + return -EINVAL; > + > + p =3D next; > + switch (*p) { > + case 'T': > + val *=3D 1024ULL; > + /* fall through */ > + case 'G': > + val *=3D 1024ULL; > + /* fall through */ > + case 'M': > + val *=3D 1024ULL; > + /* fall through */ > + case 'k': > + case 'K': > + val *=3D 1024ULL; > + p++; > + break; > + } > + > + p =3D white_spaces_skip(p); > + if (*p !=3D '\0') > + return -EINVAL; > + > + *value =3D val; > + return 0; > +} > + > +int > +parser_uint32_read(uint32_t *value, const char *p) > +{ > + uint64_t val =3D 0; > + int rc =3D parser_uint64_read(&val, p); > + > + if (rc < 0) > + return rc; > + > + if (val > UINT32_MAX) > + return -ERANGE; > + > + *value =3D val; > + return 0; > +} > + > +int > +parser_ip4_read(uint32_t *value, char *p) > +{ > + uint8_t shift =3D 24; > + uint32_t ip =3D 0; > + char *token; > + > + token =3D strtok(p, "."); > + while (token !=3D NULL) { > + ip |=3D (atoi(token) << shift); > + token =3D strtok(NULL, "."); > + shift -=3D 8; > + } > + > + *value =3D ip; > + > + return 0; > +} > + > +int > +parser_ip6_read(uint8_t *value, char *p) > +{ > + uint64_t val =3D 0; > + char *token; > + > + token =3D strtok(p, ":"); > + while (token !=3D NULL) { > + hex_string_to_uint64(&val, token); > + *value =3D val; > + token =3D strtok(NULL, ":"); > + value++; > + val =3D 0; > + } > + > + return 0; > +} > + > +int > +parser_mac_read(uint64_t *value, char *p) > +{ > + uint64_t mac =3D 0, val =3D 0; > + uint8_t shift =3D 40; > + char *token; > + > + token =3D strtok(p, ":"); > + while (token !=3D NULL) { > + hex_string_to_uint64(&val, token); > + mac |=3D val << shift; > + token =3D strtok(NULL, ":"); > + shift -=3D 8; > + val =3D 0; > + } > + > + *value =3D mac; > + > + return 0; > +} > diff --git a/app/graph/utils.h b/app/graph/utils.h > new file mode 100644 > index 0000000000..0ebb5de55a > --- /dev/null > +++ b/app/graph/utils.h > @@ -0,0 +1,14 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#ifndef APP_GRAPH_UTILS_H > +#define APP_GRAPH_UTILS_H > + > +int parser_uint64_read(uint64_t *value, const char *p); > +int parser_uint32_read(uint32_t *value, const char *p); > +int parser_ip4_read(uint32_t *value, char *p); > +int parser_ip6_read(uint8_t *value, char *p); > +int parser_mac_read(uint64_t *value, char *p); > + > +#endif > diff --git a/app/meson.build b/app/meson.build > index e4bf5c531c..728c936383 100644 > --- a/app/meson.build > +++ b/app/meson.build > @@ -17,6 +17,7 @@ endif > apps =3D [ > 'dumpcap', > 'pdump', > + 'graph', > 'proc-info', > 'test-acl', > 'test-bbdev', > diff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst > new file mode 100644 > index 0000000000..c90dc9ad7f > --- /dev/null > +++ b/doc/guides/tools/graph.rst > @@ -0,0 +1,171 @@ > +.. SPDX-License-Identifier: BSD-3-Clause > + Copyright(c) 2023 Marvell. > + > +dpdk-graph Application > +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > + > +The ``dpdk-graph`` tool is a Data Plane Development Kit (DPDK) > +application that allows exercising various graph use cases. > +This application has a generic framework to add new graph based use case= s to > +verify functionality. Each use case is defined as a ``.cli`` fi= le. > +Based on the input file, application creates a graph to cater the use ca= se. > + > +Supported Use cases > +------------------- > + * l3fwd > + > +Running the Application > +----------------------- > + > +The application has a number of command line options which can be provid= ed in > +following syntax > + > +.. code-block:: console > + > + dpdk-graph [EAL Options] -- [application options] > + > +EAL Options > +~~~~~~~~~~~ > + > +Following are the EAL command-line options that can be used in conjuncti= on > +with the ``dpdk-graph`` application. > +See the DPDK Getting Started Guides for more information on these option= s. > + > +* ``-c `` or ``-l `` > + > + Set the hexadecimal bit mask of the cores to run on. The CORELIS= T is a > + list of cores to be used. > + > +Application Options > +~~~~~~~~~~~~~~~~~~~ > + > +Following are the application command-line options: > + > +* ``-h`` > + > + Set the host IPv4 address over which telnet session can be opene= d. > + It is an optional parameter. Default host address is 0.0.0.0. > + > +* ``-p`` > + > + Set the L4 port number over which telnet session can be opened. > + It is an optional parameter. Default port is 8086. > + > +* ``-s`` > + > + Script name with absolute path which specifies the use case. It = is > + a mandatory parameter which will be used to create desired graph > + for a given use case. > + > +* ``--enable-graph-stats`` > + > + Enable graph statistics printing on console. By default graph sta= tistics are disabled. > + > +* ``--help`` > + > + Dumps application usage > + > +Supported CLI commands > +---------------------- > + > +This section provides details on commands which can be used in ``.cli`` > +file to express the requested use case configuration. > + > +.. list-table:: Exposed CLIs > + :header-rows: 1 > + :widths: auto > + > + * - Command > + - Description > + - Dynamic > + - Optional > + * - graph [bsz ] [tmo ] [coremask ] mod= el default> > + - Command to express the desired use case > + - No > + - No > + * - graph start > + - Command to start the graph. > + This command triggers that no more commands are left to be parsed= and graph > + initialization can be started now. It must be the last command in= ``.cli`` > + - No > + - No > + * - mempool size buffers cache > numa > + - Command to create mempool which will be further associated to RxQ= to dequeue the > packets > + - No > + - No > + * - ethdev rxq txq = [mtu > ] > + - Command to create DPDK port with given number of Rx and Tx queues= . Also attached > + RxQ with given mempool. Each port can have single mempool only i.= e. all RxQs will > + share the same mempool. > + - No > + - No > + * - ethdev mtu > + - Command to configure MTU of DPDK port > + - Yes > + - Yes > + * - ethdev promiscuous > + - Command to enable/disable promiscuous mode on DPDK port > + - Yes > + - Yes > + * - ethdev show > + - Command to dump current ethdev configuration > + - Yes > + - Yes > + * - ethdev ip4 addr add netmask > + - Command to configure IPv4 address on given PCI device. It is need= ed if user > + wishes to use ``ipv4_lookup`` node > + - No > + - Yes > + * - ethdev ip6 addr add netmask > + - Command to configure IPv6 address on given PCI device. It is need= ed if user > + wishes to use ``ipv6_lookup`` node > + - No > + - Yes > + * - ipv4_lookup route add ipv4 netmask via > + - Command to add a route into ``ipv4_lookup`` LPM table. It is need= ed if user > + wishes to route the packets based on LPM lookup table. > + - No > + - Yes > + * - ipv6_lookup route add ipv6 netmask via > + - Command to add a route into ``ipv6_lookup`` LPM table. It is need= ed if user > + wishes to route the packets based on LPM6 lookup table. > + - No > + - Yes > + * - neigh add ipv4 > + - Command to add a neighbour information into ``ipv4_rewrite`` node= . > + - No > + - Yes > + * - neigh add ipv6 > + - Command to add a neighbour information into ``ipv6_rewrite`` node= . > + - No > + - Yes > + * - ethdev_rx map port queue core > + - Command to add port-queue-core mapping to ``ethdev_rx`` node. ``e= thdev_rx`` > + node instance will be pinned on given core and will poll on reque= sted > + port/queue pair. > + - No > + - No > + [Nithin] Add CLI to get ethdev stats, graph stats via telnet > +Runtime configuration > +--------------------- > + > +Application allows some configuration to be modified at runtime using a = telnet session. > +Application initiates a telnet server with host address 0.0.0.0 and port= number 8086 if > +``-h`` and ``-p`` is not given otherwise user provided IPv4 address and = port number will > +be used. > + > +After successful launch of application, client can connect to using host= /port address and > +console will be accessed with prompt ``graph>``. [Nithin] Update Telnet session connection example with log > + > +Created graph for use case > +-------------------------- > + > +On the successful execution of ``.cli`` file, corresponding gra= ph will be created. > +This section mentions the created graph for each use case. > + > +l3fwd > +~~~~~ > + > +.. _figure_l3fwd_graph: > + > +.. figure:: img/graph-usecase-l3fwd.* > diff --git a/doc/guides/tools/img/graph-usecase-l3fwd.svg b/doc/guides/to= ols/img/graph- > usecase-l3fwd.svg > new file mode 100644 > index 0000000000..3b991c4cf0 > --- /dev/null > +++ b/doc/guides/tools/img/graph-usecase-l3fwd.svg > @@ -0,0 +1,210 @@ > + > + + "https://urldefense.proofpoint.com/v2/url?u=3Dhttp- > 3A__www.w3.org_Graphics_SVG_1.1_DTD_svg11.dtd&d=3DDwIDAg&c=3DnKjWec2b6R0m= OyPa > z7xtfQ&r=3DFZ_tPCbgFOh18zwRPO9H0yDx8VW38vuapifdDfc8SFQ&m=3DEe0JsG0yj736hY= MlfAp > ezlB2TtUrWk19QRB6M5nl_A9wsLObEPqlXYSqUau7ZfBV&s=3DQNoHRxZ4WaV84k- > 6IlzN8d9bMQsg8Go9iFXzE0lgT-o&e=3D "> > + > + > + > + > + > + + viewBox=3D"0.00 0.00 549.50 510.00" > xmlns=3D"https://urldefense.proofpoint.com/v2/url?u=3Dhttp- > 3A__www.w3.org_2000_svg&d=3DDwIDAg&c=3DnKjWec2b6R0mOyPaz7xtfQ&r=3DFZ_tPCb= gFOh1 > 8zwRPO9H0yDx8VW38vuapifdDfc8SFQ&m=3DEe0JsG0yj736hYMlfApezlB2TtUrWk19QRB6M= 5nl > _A9wsLObEPqlXYSqUau7ZfBV&s=3DKLiZ62_Z8HSL_a9Mq0OR-PCG_h1JavRUfbKsPOc4IAo&= e=3D > " xmlns:xlink=3D"http://www.w3.org/1999/xlink"> > + > +dpdk_app_graph_l3fwd_nodes_flow > + > + > + > +ingress_port > + 489.5,-502"/> > + size=3D"14.00">ingress_port > + > + > + > +ethdev_rx > + > + size=3D"14.00">ethdev_rx > + > + > + > +ingress_port->ethdev_rx > + 425.24"/> > + 425.18"/> > + size=3D"14.00">ingress packet > + > + > + > +pkt_cls > + > + size=3D"14.00">pkt_cls > + > + > + > +ethdev_rx->pkt_cls > + 352.07"/> > + 352.03"/> > + > + > + > +ip4_lookup > + > + size=3D"14.00">ip4_lookup > + > + > + > +pkt_cls->ip4_lookup > + 279.07"/> > + 279.03"/> > + > + > + > +ip6_lookup > + > + size=3D"14.00">ip6_lookup > + > + > + > +pkt_cls->ip6_lookup > + 335.97,-271.65"/> > + 337.39,-268.45"/> > + > + > + > +pkt_drop > + > + size=3D"14.00">pkt_drop > + > + > + > +pkt_cls->pkt_drop > + 301.02 524.5,-281.64 524.5,-252 524.5,-252 524.5,-252 524.5,-104 524.5,-5= 5.68 467.5,-34.79 > 420.91,-25.78"/> > + 22.29"/> > + > + > + > +ip4_rewrite > + > + size=3D"14.00">ip4_rewrite > + > + > + > +ip4_lookup->ip4_rewrite > + 409.79,-204.85"/> > + 412.78,-203.02"/> > + > + > + > +ip4_lookup->pkt_drop > + 222.87 463.94,-209.37 467.5,-196 471.62,-180.54 472.57,-175.18 467.5,-160= 451.61,-112.41 > 412.64,-67.99 386.65,-42.17"/> > + 39.54"/> > + > + > + > +ip6_rewrite > + > + size=3D"14.00">ip6_rewrite > + > + > + > +ip6_lookup->ip6_rewrite > + 238.52,-201.87"/> > + 240.43,-198.9"/> > + > + > + > +ip6_lookup->pkt_drop > + 214.59 314.55,-185.26 321.5,-160 332.39,-120.41 345.45,-74.7 353.61,-46.3= 2"/> > + 46.92"/> > + > + > + > +ethdev_tx > + > + size=3D"14.00">ethdev_tx > + > + > + > +ip4_rewrite->ethdev_tx > + 287.98,-124.84"/> > + 289.39,-121.63"/> > + > + > + > +ip4_rewrite->pkt_drop > + 374.03,-78.99 367.22,-46.38"/> > + 45.26"/> > + > + > + > +ip6_rewrite->ethdev_tx > + 132.14"/> > + 238.31,-133.65"/> > + > + > + > +ip6_rewrite->pkt_drop > + 140.87 169.12,-109.39 184.5,-87 210.62,-48.98 261.18,-32.21 301.59,-24.82= "/> > + 28.24"/> > + > + > + > +ethdev_tx->pkt_drop > + 313.31,-55.57 332.84,-40.75"/> > + 43.54"/> > + > + > + > +egress_port > + > + size=3D"14.00">egress_port > + > + > + > +ethdev_tx->egress_port > + 40.12"/> > + 101.03,-36.78"/> > + size=3D"14.00">egress packet > + > + > + > diff --git a/doc/guides/tools/index.rst b/doc/guides/tools/index.rst > index f2afb1fcc5..4f4dc8b518 100644 > --- a/doc/guides/tools/index.rst > +++ b/doc/guides/tools/index.rst > @@ -23,4 +23,5 @@ DPDK Tools User Guides > testeventdev > testregex > testmldev > + graph > dts > -- > 2.25.1