From patchwork Thu Jun 16 10:31:09 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Elo, Matias \(Nokia - FI/Espoo\)" X-Patchwork-Id: 70174 Delivered-To: patch@linaro.org Received: by 10.140.28.4 with SMTP id 4csp186458qgy; Thu, 16 Jun 2016 03:32:41 -0700 (PDT) X-Received: by 10.233.222.4 with SMTP id s4mr3716239qkf.74.1466073161486; Thu, 16 Jun 2016 03:32:41 -0700 (PDT) Return-Path: Received: from lists.linaro.org (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTP id s92si25872287qgs.116.2016.06.16.03.32.41; Thu, 16 Jun 2016 03:32:41 -0700 (PDT) Received-SPF: pass (google.com: domain of lng-odp-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) client-ip=54.225.227.206; Authentication-Results: mx.google.com; spf=pass (google.com: domain of lng-odp-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) smtp.mailfrom=lng-odp-bounces@lists.linaro.org; dmarc=fail (p=NONE dis=NONE) header.from=nokia.com Received: by lists.linaro.org (Postfix, from userid 109) id 15366687A2; Thu, 16 Jun 2016 10:32:41 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on ip-10-142-244-252 X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAD_ENC_HEADER,BAYES_00, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_PASS,URIBL_BLOCKED autolearn=disabled version=3.4.0 Received: from [127.0.0.1] (localhost [127.0.0.1]) by lists.linaro.org (Postfix) with ESMTP id 7265F616D2; Thu, 16 Jun 2016 10:32:31 +0000 (UTC) X-Original-To: lng-odp@lists.linaro.org Delivered-To: lng-odp@lists.linaro.org Received: by lists.linaro.org (Postfix, from userid 109) id 4B0C868182; Thu, 16 Jun 2016 10:32:29 +0000 (UTC) Received: from emea01-db3-obe.outbound.protection.outlook.com (mail-db3on0148.outbound.protection.outlook.com [157.55.234.148]) by lists.linaro.org (Postfix) with ESMTPS id 7AE2861588 for ; Thu, 16 Jun 2016 10:31:56 +0000 (UTC) Received: from VI1PR07CA0069.eurprd07.prod.outlook.com (10.164.94.165) by VI1PR07MB1069.eurprd07.prod.outlook.com (10.163.168.17) with Microsoft SMTP Server (TLS) id 15.1.517.8; Thu, 16 Jun 2016 10:31:54 +0000 Received: from AM1FFO11OLC006.protection.gbl (2a01:111:f400:7e00::137) by VI1PR07CA0069.outlook.office365.com (2a01:111:e400:5967::37) with Microsoft SMTP Server (TLS) id 15.1.523.12 via Frontend Transport; Thu, 16 Jun 2016 10:31:54 +0000 Received-SPF: Pass (protection.outlook.com: domain of nokia.com designates 131.228.2.241 as permitted sender) receiver=protection.outlook.com; client-ip=131.228.2.241; helo=mailrelay.int.nokia.com; Received: from mailrelay.int.nokia.com (131.228.2.241) by AM1FFO11OLC006.mail.protection.outlook.com (10.174.64.134) with Microsoft SMTP Server (TLS) id 15.1.511.7 via Frontend Transport; Thu, 16 Jun 2016 10:31:53 +0000 Received: from fihe3nok0735.emea.nsn-net.net (localhost [127.0.0.1]) by fihe3nok0735.emea.nsn-net.net (8.14.9/8.14.5) with ESMTP id u5GAVAi8008016 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Thu, 16 Jun 2016 13:31:10 +0300 Received: from 10.144.19.15 ([10.144.104.92]) by fihe3nok0735.emea.nsn-net.net (8.14.9/8.14.5) with ESMTP id u5GAVA96008013 (version=TLSv1/SSLv3 cipher=AES128-SHA256 bits=128 verify=NOT) for ; Thu, 16 Jun 2016 13:31:10 +0300 X-HPESVCS-Source-Ip: 10.144.104.92 From: Matias Elo To: Date: Thu, 16 Jun 2016 13:31:09 +0300 Message-ID: <1466073070-20148-1-git-send-email-matias.elo@nokia.com> X-Mailer: git-send-email 1.9.1 X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:131.228.2.241; IPV:NLI; CTRY:FI; EFV:NLI; SFV:NSPM; SFS:(10019020)(6009001)(7916002)(2980300002)(438002)(199003)(189002)(189998001)(586003)(81166006)(16796002)(8676002)(106466001)(47776003)(81156014)(2351001)(229853001)(50986999)(6806005)(22756006)(5008740100001)(356003)(87936001)(97736004)(33646002)(107886002)(110136002)(92566002)(68736007)(2906002)(450100001)(36756003)(77096005)(48376002)(50466002)(11100500001)(50226002)(19580405001)(5003940100001)(19580395003)(8936002)(42882005); DIR:OUT; SFP:1102; SCL:1; SRVR:VI1PR07MB1069; H:mailrelay.int.nokia.com; FPR:; SPF:Pass; PTR:InfoDomainNonexistent; A:1; MX:1; CAT:NONE; LANG:en; CAT:NONE; X-Microsoft-Exchange-Diagnostics: 1; AM1FFO11OLC006; 1:AM+NCWYSb8DNJDfq6PVs7Hk2n65oet0Rqo9nRn4VwD7/qpUCp1thII/TWDdUU9TguomjK+rgQNdj6c2W954ZwCli9VlbuPg6mEfa5x/L2zdZqokD+anup0caVsTEG5zN7pCji7ISiodBZ2SeE1YbWwEpsNLyHaEszexMNyclttwA2EF1orRVacabg/V5yhjqUzbBQe1PkrhDNx/LKp9a5ZQcf2uLvspvmfwbne3tYxOvFJJG6m5IlFHpbJIjyWNNOl9VEnt7DJ/OEJ6G5uK5+EE57bkoz4uX96g+S6TVAHRPcTOa/Vz/uch9tkTITxVuH2m6UxhlWHCj9pmcasPaC9ixqxOpRJM9SmjOeE+GSkirGDL3YmmDpqY3v+AYHxyUO5UoIK4rjJgOh3oVxUAXsEmhVusfA04rDExLjkUbXxs= MIME-Version: 1.0 X-MS-Office365-Filtering-Correlation-Id: 4a2b953d-0396-410e-d713-08d395d16f7c X-Microsoft-Exchange-Diagnostics: 1; VI1PR07MB1069; 2:QNNbjs4BxNWD3njouYuQ8Ha/vsbbseWQIQBSb8rULXPwnPP/gcZtOyChN5TC9G4M3j00G9K1FooxgC7ZAQEhlPLI7NVHBJ/He7iyYIhv4vcS0BfTWPU6wXPv6YQW2dHzjxKOeOxUgdZPrMlRbAeCQAE9DUqloCh+dL4GI8XnBjFHbV8tImfS1gT2T29Ncpct; 3:+DoHPN0t9iTY/kf8t7VfzoZiiCND31nNtVsyKUB3bbdLjWIXurqk3uBOVSwQFsrn6sT4E3kzjxgiX9pupPNHtJKRYlV8OBe1qPWYrlI4LMdG1HOlBJRT/2j2pCB8Kt8Mo3+EorZ1UPIQgvn6PsLzNcrkqkJksX0g7uQ/N4ZNjLE//tZFNffra4mjkHBsICOZBc74OVxc6Sd0/SxScg4AtuCa2fvH5hV9c/IoScnBaastx6Ny3vAi1xDGjVip6E0h/Pf95JDF7a7+0oLhMrUE4A== X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(8251501002); SRVR:VI1PR07MB1069; X-Microsoft-Exchange-Diagnostics: 1; VI1PR07MB1069; 25:tERUayPv5siHVxTH8FjF8nJokih2D8WK2H6PbQDLE4nAr48Icnmhux9er1WLz7iI7E6hUl0VplQno0/ylJ1ylbe7JDe3/9xsjx5TfksGk6d96D/JAdlLVJQwzTzgxoOuCrTUNiEUvDt9h9vbGViyj2DBgmPAFkaGc5Plg31B3pt8tuMkEaqqSP0LjTpHQJKmnYwc1JH3PTfiJ217p3OWvNehleoMo5mMfyxMEaFCvMbao4BfxyFuX1wbu8ljncJKDOd5EMd4STaXrrJZJHNaZVZxEfn2BrzSwWd0UDe/JxsMke9p2mFteTBy8ehq5J9y5ln2s/C2nJylQqDhzDg2wBy8lHQsHagGE2OVLNvqsZmwJqCi3wtwrDQSDflchFqopHHR4cSDnf1/yv/Hh0oARVkuZ0FrfP1x/7HpcdH0iGLEhfiGKR4XX7efyossWljzCQi19Zrk0PuGqc9igFxohm4Kc1fga453Wt8h3S4yFPxMf3K7+WJC8peWMgWBUgVNNvW9m7wA7+/dE/2tCU4ajroS07SntB38tm0sDQ0FtqsMR7PFsrlRKZXE1jT/RziJ40MyhtySNjIWHf3FhY8DWyUvbhVWGYY5hh8s/RXRY9eVNdbH/YtL9rz8OUsYJh+bAVBIQYWb/UI70TaIhFJRy6VyMS1w+iqjafSzkeNqWu96FnjX2vzA6D2M5zlO+q7C1cFTdt86CssxrFOVxYHTEFaeCLmtE7Wo7mKBKKwHxKcV0kjaRBRrFyr0x/lpzkwtVuOrc0UHzdOl1DLRgZFyBm7opRAjq6acxEkAGnmOZQI= X-Microsoft-Exchange-Diagnostics: 1; VI1PR07MB1069; 20:5mNiVeFxjKZiyf6AxjUGjZaT2MP9FkJfRbuFt0+h+5RqXVBdCQpQZSgNV1kXXu6BLlDS2mkpxbUzgEUf9Fx7yMoOV9VB7VHgu3dztu68ffXNPCgX+mzx7V9mzDdHnR5ploX0K8PW5LRO9gPryPVvlZoLKmxfO7UrlM3WoQ5qVDIftATFZMizNBmbHBztjQCzRxbX+YQ9k6J2cHHjAWe7kIGb1b3S8wG1M26ZHCixDJ8QmIXoY7V/CS+ekLU/1RpX3VdCjhMHlkLHzNLalv2Vpjv/vcPH9Lz/HX6MDDAFzmkTk9Mg2pvUXdXlASgqzCxq1mz3Pj1judgWnk20ocB57+UyyEJeRMXRng0KEVJM+Jkvan6r5oeP9rm5Hx/MUZhIh+k903rpqTr8pKDYhWQnJeXVN45pSIu6ortWNilPWzzxixzNdc/lZtyjCieP8wDEX0RosLce/cevpZkWKvy+jc0N2z/XOhKsHJmtAXDMun1oVPaC2UmWif3jMENlvhc7vceF5vmdJhfjgfq7NxIGo8m8qoU4TDbJXcHD+XuEzXNxpqvTcsCJs5qY1AnsQGjmqXB9sqzSeOOOJURC9kHyHBeDmlaXbPJ7TI/OKPFs8SE= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(82608151540597); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(5005006)(8121501046)(13018025)(13016025)(10201501046)(3002001); SRVR:VI1PR07MB1069; BCL:0; PCL:0; RULEID:; SRVR:VI1PR07MB1069; X-Microsoft-Exchange-Diagnostics: 1; VI1PR07MB1069; 4:O7M4cPsjgOJdMm1KqxggKGMpm0eMhx40sRrpDQ695kzhKrHaoGN0M3k7hLu3qxKIVk0BYPcgzTEmRqm+IzHXMTW+VgkcGfjCjRIOH7unrmaAlZCdfI+awgR0FuWYyqq9m4aI/449TIIhnN9HnBHqBlZvbAlsmNbWbJhjR7ziYcRoMjcpGq5sExPlpYfB6EPNENveaQAgbCRFBsxoe+7RQpBEccae3tvZ+JjyshJNUbfACOQxNcZetxdDlhYKbg0SIZxSH8ZsDlFVIeqjwLzKDacmraWpR50E1bpnryHp4xFrx03BtBDtZo3uj7COyBcGGd2MQwcXZHNUzE74rmlfS2m9R9mJcqLeIfzkqkIQvlVtFZK1CgkZnxmpq9XYRwvNpH7LeQogP5PchLCK7o7m51mhe506w982dr6XplMjIC0+3VrqiAhszBunZfclxCmOSYNSroo0Lt3fbWo9P+yW8Q== X-Forefront-PRVS: 09752BC779 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; VI1PR07MB1069; 23:DjB5Kra+LnQTkgHXztUjKMPzeGm5zNbXOfsJUs1af?= =?us-ascii?Q?2xBr5idsaeqwxonwsbgkAhbxjrzeRKFW43LkxM+OK5FG8kM2JDARJN8hb7nD?= =?us-ascii?Q?3Lyb0JA4LFcZIa/A5MGDB+tr1jGuBR31r1mh3SkAEFsuotprkZtEvDrpYKrV?= =?us-ascii?Q?s5D7bEnV9hGP/AWQ/kfhX6AqXzijMRTgcAsm+/vGK3uW06PLhM5wrQpEmBY+?= =?us-ascii?Q?bdXNcng734pOQgwHRDXDOWVocyu/pelaQewt4Q5SnttlWHnYiWVTABP9Ig1y?= =?us-ascii?Q?8KFJeiOFf5rXkE2RI2a+qcp5vcNqGZXgriHBIADNXDNBjylQdZwsKWqBpZ9/?= =?us-ascii?Q?ML/UKntIiGXueWRlvO7oR0+ce6jsvzM9NDpYC5duPOt9LfplENHw8BeXzvVI?= =?us-ascii?Q?jcQGY7Qqjlo5n1LjfnnvWW5UZP/+NRdswScDfE4E3NFirrpRuR0dMYuvq9rB?= =?us-ascii?Q?bSREVusHSDD/U3dHE0+hwQtFG+EZAGU9096IxDIjBEAwRI4G8vImBZBqM3eA?= =?us-ascii?Q?Gh+XL5wwZ2NT4PDBL6IE1P+NBE69NR6y55xlIRn1Qn6x6o3RfIRzCAj/cpNq?= =?us-ascii?Q?oXYE1SXNLIX6x71MLhUFbtXXv7wU7zuNewv+GudYF8QvoqDdko6yfeRSiVPc?= =?us-ascii?Q?FVj3ZkjRGk4ONM3AbgXVvdO1X3cjziswva0/03gSxsIk5OP24uUVjzEz4lR1?= =?us-ascii?Q?H526miLb31gBFoFXEA41YG/wN02rVwNluPl1Zyl2Pk9q2CTp0SnRcYYuiDSB?= =?us-ascii?Q?9JRmeWVy8go0yWsFh1rXCZG1YFrOWoAcSrUoURi5XcJZ1BTs/axaYowHwTTS?= =?us-ascii?Q?tlWR1u2kpE2weragffb/aBm047phfxwkyWCwqGhhYDWvCoMVuVeE5apmh8y5?= =?us-ascii?Q?lmuPMRRNY8ULrxb5U/vtHSWvmp/SoDUgDbwnkm8fFyDuuAgx+AZCnjEV0Oib?= =?us-ascii?Q?wGNsTf6zUxzdyv8WCCBXwMzcyFUb9DK5p1QuWv16vyUEMTN73DJKONEOO82Z?= =?us-ascii?Q?r1WRlgUtM9tbWr3Th9Cs5dCg0iri/ZgGizwWH5LFmD3rsS2z49l9a38MvrX5?= =?us-ascii?Q?q7z3Pc=3D?= X-Microsoft-Exchange-Diagnostics: 1; VI1PR07MB1069; 6:lTDibCOJbd4THktygomeR7QGvBaBgFqWUV9LoJQe5Q2YlBWDH+H1Eerxxa6fPJbrEEoLeEkVy7MupPNwVHLrVtCuLSnz6D3Dl9cXcyd7Npe1NBlkmEQKrkp1rwQ5bEsp/l/llCCsN3F+1EYc5MLWZx4pU8XQQQcwbea8yBvnY68UmnmSbAKLLqR+/cgS6D8n70iYCu8/rM1jXA96EdHs5GhfyPzXNDeXfEUoJYrifjqFvg/S8PiKTL2/txjSAVJl3EooVFS8Ju/WFjCz3P9hK+p2NVybjuEum+EYPZ1MX5w=; 5:Nt9s5cTRa+/luq88Bnk/sEwV3/2qrlSY2K5iESNuyFqgZl+11nReJ/MHiGgHp5IhQOAEmloGIXMzgUFrgGC69rx4cS+RsjhBzGhAKZbSrLVOly08JkUYLYisrjk+vDUecyQ7SQJPqP6W9TEaV2AyGw==; 24:yWLbbw/rCQAhyCwa0wufo1emhuErvmxSGXcgVer6wapLt3KCxk4sSE6CAQI0TM5/xqfu6ljYgbBLAd68x5CRnOSDw35isJgDEUhdo8XHcMw=; 7:esRnPvJYkrfnaHJoKTPuwJojSBG5MhIRLlIcQ3aJ9PnKAtYqpHZZMsELWTibx231kfuzQm5Bo7PpfKwEpF4MIcb3MlAfiXnala/CGE0iyCRdHNL3QTI5l6G5BPL6jd8Fia0BSdkaVGkshVsPQpjv7vDttP84WeTFwtunvXbxAq5qnKoUjrbQRgj10SOBQ8ZqXgKyp3EQ9FCDnhDqqYmggg== SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: nokia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Jun 2016 10:31:53.8967 (UTC) X-MS-Exchange-CrossTenant-Id: 5d471751-9675-428d-917b-70f44f9630b0 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=5d471751-9675-428d-917b-70f44f9630b0; Ip=[131.228.2.241]; Helo=[mailrelay.int.nokia.com] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR07MB1069 X-Topics: patch Subject: [lng-odp] [PATCH 1/2] example: echo: add new L2 echo example application X-BeenThere: lng-odp@lists.linaro.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: "The OpenDataPlane \(ODP\) List" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: lng-odp-bounces@lists.linaro.org Sender: "lng-odp" Added new L2 echo example application which works in the same manner as standard L3 ping utility. The application has two modes transmitter and responder. In transmitter mode the application sends echo packets from selected interface and waits for responses. When a response is received RTT measurement is printed. In responder mode the application merely resends received echo packets back to the transmitter. Signed-off-by: Matias Elo --- example/Makefile.am | 2 +- example/echo/.gitignore | 1 + example/echo/Makefile.am | 10 + example/echo/odp_echo.c | 528 +++++++++++++++++++++++++++++++++++++++++++++++ example/m4/configure.m4 | 3 +- 5 files changed, 542 insertions(+), 2 deletions(-) create mode 100644 example/echo/.gitignore create mode 100644 example/echo/Makefile.am create mode 100644 example/echo/odp_echo.c diff --git a/example/Makefile.am b/example/Makefile.am index 7f82c4d..ab37f21 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -1 +1 @@ -SUBDIRS = classifier generator ipsec packet time timer traffic_mgmt l2fwd_simple switch +SUBDIRS = classifier generator ipsec packet time timer traffic_mgmt l2fwd_simple switch echo diff --git a/example/echo/.gitignore b/example/echo/.gitignore new file mode 100644 index 0000000..b1e5eb5 --- /dev/null +++ b/example/echo/.gitignore @@ -0,0 +1 @@ +odp_echo diff --git a/example/echo/Makefile.am b/example/echo/Makefile.am new file mode 100644 index 0000000..323522f --- /dev/null +++ b/example/echo/Makefile.am @@ -0,0 +1,10 @@ +include $(top_srcdir)/example/Makefile.inc + +bin_PROGRAMS = odp_echo$(EXEEXT) +odp_echo_LDFLAGS = $(AM_LDFLAGS) -static +odp_echo_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/example + +noinst_HEADERS = \ + $(top_srcdir)/example/example_debug.h + +dist_odp_echo_SOURCES = odp_echo.c diff --git a/example/echo/odp_echo.c b/example/echo/odp_echo.c new file mode 100644 index 0000000..cc966e1 --- /dev/null +++ b/example/echo/odp_echo.c @@ -0,0 +1,528 @@ +/* Copyright (c) 2016, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#include +#include +#include +#include + +#define POOL_NUM_PKT 256 +#define POOL_SEG_LEN 1856 + +#define MAX_WORKERS 2 + +#define ECHO_PACKET_LEN 64 +#define ECHO_MAGIC 0x92749451 +#define ECHO_TX_INTERVAL ODP_TIME_SEC_IN_NS + +/** + * Application mode + */ +typedef enum appl_mode_t { + TRANSMIT, + RESPOND +} appl_mode_t; + +/** Get rid of path in filename - only for unix-type paths using '/' */ +#define NO_PATH(file_name) (strrchr((file_name), '/') ? \ + strrchr((file_name), '/') + 1 : (file_name)) + +/** + * Parsed command line application arguments + */ +typedef struct { + char *if_str; /**< Storage for interface name */ + odph_ethaddr_t dst; /**< Destination MAC address */ + appl_mode_t mode; /**< Application mode */ + uint64_t wait; /**< Wait new packets */ + int burst_size; /**< Packet burst size */ +} appl_args_t; + +/** + * Global application data + */ +struct { + appl_args_t appl; /**< Parsed application arguments */ + odp_pktio_t iface; /**< Pktio handle */ + odph_ethaddr_t src; /**< Source MAC address */ + odp_pktin_queue_t pktin; /**< Packet input queue */ + odp_pktout_queue_t pktout; /**< packet output queue */ + odp_pool_t pool; /**< Packet pool */ +} global; + +/** + * Echo packet header + */ +typedef struct ODP_PACKED { + uint32_t llc; /**< LLC header */ + uint32_t magic; /**< Magic number for verifying echo packets */ + uint32_t seq; /**< Sequence number */ + uint64_t ts; /**< Timestamp (ns) */ +} echo_hdr_t; + +/** + * Create a pktio handle + * + * @param dev Device name + * @param pool Associated Packet Pool + * @param pktin[out] Packet input queue + * @param pktout[out] Packet output queue + * + * @return The handle of the created pktio object. + */ +static odp_pktio_t create_pktio(const char *name, odp_pool_t pool, + odp_pktin_queue_t *pktin, + odp_pktout_queue_t *pktout) +{ + odp_pktio_param_t pktio_param; + odp_pktin_queue_param_t in_queue_param; + odp_pktout_queue_param_t out_queue_param; + odp_pktio_t pktio; + + odp_pktio_param_init(&pktio_param); + + pktio = odp_pktio_open(name, pool, &pktio_param); + if (pktio == ODP_PKTIO_INVALID) { + printf("Error: failed to open %s\n", name); + exit(1); + } + /* Configure one input queue */ + odp_pktin_queue_param_init(&in_queue_param); + in_queue_param.op_mode = ODP_PKTIO_OP_MT_UNSAFE; + in_queue_param.num_queues = 1; + if (odp_pktin_queue_config(pktio, &in_queue_param)) { + printf("Error: failed to config input queue for %s\n", name); + exit(1); + } + /* Configure one output queue */ + odp_pktout_queue_param_init(&out_queue_param); + out_queue_param.op_mode = ODP_PKTIO_OP_MT_UNSAFE; + out_queue_param.num_queues = 1; + if (odp_pktout_queue_config(pktio, &out_queue_param)) { + printf("Error: failed to config output queue for %s\n", name); + exit(1); + } + /* Save input and output queue handles */ + if (odp_pktin_queue(pktio, pktin, 1) != 1) { + printf("Error: pktin queue query failed for %s\n", name); + exit(1); + } + if (odp_pktout_queue(pktio, pktout, 1) != 1) { + printf("Error: pktout queue query failed for %s\n", name); + exit(1); + } + return pktio; +} + +/** + * Initialize echo packet headers + * + * @param pkt Packet handle + * + * @retval 0 on success + * @retval <0 on failure + */ +static uint32_t echo_packet_init(odp_packet_t pkt) +{ + odph_ethhdr_t *eth; + echo_hdr_t echo; + static uint32_t seq_num; + + /* Ethernet headers */ + eth = odp_packet_data(pkt); + eth->src = global.src; + eth->dst = global.appl.dst; + eth->type = odp_cpu_to_be_16(odp_packet_len(pkt) - ODPH_ETHHDR_LEN); + + /* Echo headers */ + echo.llc = 0; /* NULL DSAP, SSAP and control fields */ + echo.magic = ECHO_MAGIC; + echo.seq = seq_num++; + echo.ts = odp_time_to_ns(odp_time_global()); + + if (odp_packet_copy_from_mem(pkt, ODPH_ETHHDR_LEN, sizeof(echo), + &echo) != 0) { + printf("Error: copying echo header failed\n"); + return -1; + } + return 0; +} + +/** + * Echo header start pointer + * + * @param pkt Packet handle + * + * @return Echo header start pointer + * @retval NULL packet does not contain a valid echo header + */ +static echo_hdr_t *echo_hdr(odp_packet_t pkt) +{ + odph_ethhdr_t *eth; + echo_hdr_t *echo; + + eth = odp_packet_l2_ptr(pkt, NULL); + echo = (echo_hdr_t *)(eth + 1); + + if (echo->magic != ECHO_MAGIC) + return NULL; + + return echo; +} + +/** + * Echo packet responder thread + */ +static int run_responder(void *arg ODP_UNUSED) +{ + odp_packet_t pkt_tbl[global.appl.burst_size]; + odp_packet_t tx_tbl[global.appl.burst_size]; + int pkts, sent, tx_drops, i; + + printf("\n*** Echo responder started ***\n\n"); + + for (;;) { + int num_rx = 0; + + pkts = odp_pktin_recv_tmo(global.pktin, pkt_tbl, + global.appl.burst_size, + global.appl.wait); + + if (odp_unlikely(pkts <= 0)) + continue; + for (i = 0; i < pkts; i++) { + odp_packet_t pkt = pkt_tbl[i]; + odph_ethhdr_t *eth; + + if (odp_unlikely(!odp_packet_has_eth(pkt))) { + odp_packet_free(pkt); + continue; + } + eth = odp_packet_l2_ptr(pkt, NULL); + + if (echo_hdr(pkt) == NULL) { + odp_packet_free(pkt); + continue; + } + + /* Swap MAC addresses */ + eth->dst = eth->src; + eth->src = global.src; + + tx_tbl[num_rx++] = pkt; + } + sent = odp_pktout_send(global.pktout, tx_tbl, num_rx); + if (odp_unlikely(sent < 0)) + sent = 0; + tx_drops = num_rx - sent; + if (odp_unlikely(tx_drops)) + odp_packet_free_multi(&tx_tbl[sent], tx_drops); + } + return 0; +} + +/** + * Echo packet transmitter thread + */ +static int run_transmitter(void *arg ODP_UNUSED) +{ + for (;;) { + odp_packet_t pkt; + int sent; + + pkt = odp_packet_alloc(global.pool, ECHO_PACKET_LEN); + if (pkt == ODP_PACKET_INVALID) + continue; + + if (echo_packet_init(pkt)) { + odp_packet_free(pkt); + continue; + } + + sent = odp_pktout_send(global.pktout, &pkt, 1); + if (odp_unlikely(sent != 1)) + odp_packet_free(pkt); + + odp_time_wait_ns(ECHO_TX_INTERVAL); + } + return 0; +} + +/** + * Echo packet receiver thread + */ +static int run_receiver(void *arg ODP_UNUSED) +{ + odp_packet_t pkt_tbl[global.appl.burst_size]; + int pkts, i; + + for (;;) { + uint64_t ts; + + pkts = odp_pktin_recv_tmo(global.pktin, pkt_tbl, + global.appl.burst_size, + global.appl.wait); + + if (odp_unlikely(pkts <= 0)) + continue; + + ts = odp_time_to_ns(odp_time_global()); + + for (i = 0; i < pkts; i++) { + odp_packet_t pkt = pkt_tbl[i]; + odph_ethhdr_t *eth; + odph_ethaddr_t *src; + echo_hdr_t *echo; + double delay; + + if (odp_unlikely(!odp_packet_has_eth(pkt))) + continue; + eth = odp_packet_l2_ptr(pkt, NULL); + + echo = echo_hdr(pkt); + if (!echo) + continue; + + delay = (double)(ts - echo->ts) / ODP_TIME_MSEC_IN_NS; + src = ð->src; + + printf("%" PRIu32 " bytes from " + "%02x:%02x:%02x:%02x:%02x:%02x: seq=%" PRIu32 " " + "time=%0.3f ms\n", odp_packet_len(pkt), + src->addr[0], src->addr[1], src->addr[2], + src->addr[3], src->addr[4], src->addr[5], + echo->seq, delay); + } + odp_packet_free_multi(pkt_tbl, pkts); + } + return 0; +} + +/** + * Print usage information + */ +static void usage(char *progname) +{ + printf("\n" + "OpenDataPlane echo example application.\n" + "\n" + "Usage: %s OPTIONS\n" + " E.g. host1$ %s -m 0 -i eth0 -d 02:01:02:03:04:05\n" + " host2$ %s -m 1 -i eth1\n\n" + " In the above example,\n" + " host1 sends echo packets from eth0 to the MAC address of\n" + " host2's eth1 and waits for responses. Host2 waits for echo\n" + " packets from eth1 and resends them back to the sender.\n" + "\n" + "Mandatory OPTIONS:\n" + " -i, --interface Eth interface\n" + " -d, --destination Destination MAC address (required in transmitter mode)\n" + "\n" + "Optional OPTIONS:\n" + " -m, --mode 0: Transmitter (default)\n" + " 1: Responder\n" + " -n, --no-wait Busy wait new packets\n" + " -b, --burst Receive burst size\n" + " -h, --help Display help and exit.\n\n" + "\n", NO_PATH(progname), NO_PATH(progname), NO_PATH(progname)); +} + +/** + * Parse and store the command line arguments + * + * @param argc argument count + * @param argv[] argument vector + * @param appl_args Store application arguments here + */ +static void parse_args(int argc, char *argv[], appl_args_t *appl_args) +{ + int opt; + int long_index; + size_t len; + int i; + odp_bool_t mac_set = 0; + static const char *shortopts = "+m:i:d:b:nh"; + static const struct option longopts[] = { + {"mode", required_argument, NULL, 'm'}, + {"interface", required_argument, NULL, 'i'}, + {"destination", required_argument, NULL, 'd'}, + {"burst", required_argument, NULL, 'b'}, + {"no-wait", no_argument, NULL, 'n'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + appl_args->if_str = NULL; + appl_args->burst_size = 1; + appl_args->wait = ODP_PKTIN_WAIT; + + /* let helper collect its own arguments (e.g. --odph_proc) */ + odph_parse_options(argc, argv, shortopts, longopts); + + opterr = 0; /* do not issue errors on helper options */ + + while (1) { + opt = getopt_long(argc, argv, shortopts, longopts, &long_index); + + if (opt == -1) + break; /* No more options */ + + switch (opt) { + case 'm': + i = atoi(optarg); + if (i == 1) + appl_args->mode = RESPOND; + else + appl_args->mode = TRANSMIT; + break; + case 'i': + len = strlen(optarg); + if (len == 0) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + len += 1; /* add room for '\0' */ + + appl_args->if_str = malloc(len); + if (appl_args->if_str == NULL) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + strcpy(appl_args->if_str, optarg); + break; + case 'd': + if (odph_eth_addr_parse(&appl_args->dst, optarg)) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + mac_set = 1; + + break; + case 'b': + i = atoi(optarg); + if (i < 1) + appl_args->burst_size = 1; + else + appl_args->burst_size = i; + break; + case 'n': + appl_args->wait = ODP_PKTIN_NO_WAIT; + break; + case 'h': + usage(argv[0]); + exit(EXIT_SUCCESS); + break; + default: + break; + } + } + + if (appl_args->if_str == NULL || + (appl_args->mode == TRANSMIT && !mac_set)) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + optind = 1; /* reset 'extern optind' from the getopt lib */ +} + +int main(int argc, char **argv) +{ + odph_odpthread_t thread_tbl[MAX_WORKERS]; + odp_pool_param_t params; + odp_cpumask_t cpumask; + odp_instance_t instance; + int i; + int cpu; + int num_workers; + int req_workers; + + /* Initialize ODP */ + if (odp_init_global(&instance, NULL, NULL)) { + printf("Error: ODP global init failed.\n"); + exit(1); + } + + if (odp_init_local(instance, ODP_THREAD_CONTROL)) { + printf("Error: ODP local init failed.\n"); + exit(1); + } + + /* Parse and store the application arguments */ + parse_args(argc, argv, &global.appl); + + /* Create packet pool */ + odp_pool_param_init(¶ms); + params.pkt.seg_len = POOL_SEG_LEN; + params.pkt.len = POOL_SEG_LEN; + params.pkt.num = POOL_NUM_PKT; + params.type = ODP_POOL_PACKET; + + global.pool = odp_pool_create("packet pool", ¶ms); + + if (global.pool == ODP_POOL_INVALID) { + printf("Error: packet pool create failed.\n"); + exit(1); + } + + /* Create and configure pktio device */ + global.iface = create_pktio(global.appl.if_str, global.pool, + &global.pktin, &global.pktout); + + /* Save interface ethernet address */ + if (odp_pktio_mac_addr(global.iface, &global.src, + ODPH_ETHADDR_LEN) != ODPH_ETHADDR_LEN) { + printf("Error: interface ethernet address unknown\n"); + exit(EXIT_FAILURE); + } + + if (odp_pktio_start(global.iface)) { + printf("Error: unable to start input interface\n"); + exit(1); + } + + /* Create and bind worker threads */ + req_workers = global.appl.mode == TRANSMIT ? 2 : 1; + num_workers = odp_cpumask_default_worker(&cpumask, MAX_WORKERS); + + if (num_workers < req_workers) { + printf("Error: not enough workers (%d available, %d required)\n", + num_workers, req_workers); + exit(1); + } + + cpu = odp_cpumask_first(&cpumask); + for (i = 0; i < req_workers; i++) { + odp_cpumask_t thd_mask; + odph_odpthread_params_t thr_params; + + memset(&thr_params, 0, sizeof(thr_params)); + + if (global.appl.mode == RESPOND) + thr_params.start = run_responder; + else + thr_params.start = i % 2 ? run_transmitter : + run_receiver; + + thr_params.arg = NULL; + thr_params.thr_type = ODP_THREAD_WORKER; + thr_params.instance = instance; + + odp_cpumask_zero(&thd_mask); + odp_cpumask_set(&thd_mask, cpu); + odph_odpthreads_create(&thread_tbl[i], &thd_mask, + &thr_params); + cpu = odp_cpumask_next(&cpumask, cpu); + } + + odph_odpthreads_join(thread_tbl); + + return 0; +} diff --git a/example/m4/configure.m4 b/example/m4/configure.m4 index 9731d81..d54ea72 100644 --- a/example/m4/configure.m4 +++ b/example/m4/configure.m4 @@ -19,4 +19,5 @@ AC_CONFIG_FILES([example/classifier/Makefile example/timer/Makefile example/traffic_mgmt/Makefile example/l2fwd_simple/Makefile - example/switch/Makefile]) + example/switch/Makefile + example/echo/Makefile])