From patchwork Thu May 19 13:02:11 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Forrest Shi X-Patchwork-Id: 68105 Delivered-To: patch@linaro.org Received: by 10.140.92.199 with SMTP id b65csp3047191qge; Thu, 19 May 2016 00:32:51 -0700 (PDT) X-Received: by 10.107.10.208 with SMTP id 77mr8876557iok.51.1463643171187; Thu, 19 May 2016 00:32:51 -0700 (PDT) Return-Path: Received: from lists.linaro.org (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTP id u188si23450876itb.54.2016.05.19.00.32.50; Thu, 19 May 2016 00:32:51 -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=pass (p=NONE dis=NONE) header.from=linaro.org Received: by lists.linaro.org (Postfix, from userid 109) id E9427617D3; Thu, 19 May 2016 07:32:49 +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.1 required=5.0 tests=BAD_ENC_HEADER,BAYES_00, DATE_IN_FUTURE_03_06, 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 E451461661; Thu, 19 May 2016 07:32:37 +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 5206C61694; Thu, 19 May 2016 07:32:35 +0000 (UTC) Received: from na01-bn1-obe.outbound.protection.outlook.com (mail-bn1on0091.outbound.protection.outlook.com [157.56.110.91]) by lists.linaro.org (Postfix) with ESMTPS id A03DB61645 for ; Thu, 19 May 2016 07:32:32 +0000 (UTC) Received: from BN3PR0301CA0014.namprd03.prod.outlook.com (10.160.180.152) by BN1PR0301MB0593.namprd03.prod.outlook.com (10.160.170.20) with Microsoft SMTP Server (TLS) id 15.1.492.11; Thu, 19 May 2016 07:32:31 +0000 Received: from BN1BFFO11FD024.protection.gbl (2a01:111:f400:7c10::1:132) by BN3PR0301CA0014.outlook.office365.com (2a01:111:e400:4000::24) with Microsoft SMTP Server (TLS) id 15.1.497.12 via Frontend Transport; Thu, 19 May 2016 07:32:31 +0000 Received-SPF: SoftFail (protection.outlook.com: domain of transitioning linaro.org discourages use of 192.88.158.2 as permitted sender) Received: from az84smr01.freescale.net (192.88.158.2) by BN1BFFO11FD024.mail.protection.outlook.com (10.58.144.87) with Microsoft SMTP Server (TLS) id 15.1.497.8 via Frontend Transport; Thu, 19 May 2016 07:32:30 +0000 Received: from netperf2.ap.freescale.net ([10.232.133.164]) by az84smr01.freescale.net (8.14.3/8.14.0) with ESMTP id u4J7WR3Z031767; Thu, 19 May 2016 00:32:28 -0700 From: To: Date: Thu, 19 May 2016 18:32:11 +0530 Message-ID: <1463662931-1183-1-git-send-email-forrest.shi@linaro.org> X-Mailer: git-send-email 2.8.2 X-EOPAttributedMessage: 0 X-Matching-Connectors: 131081167510189936; (91ab9b29-cfa4-454e-5278-08d120cd25b8); () X-Forefront-Antispam-Report: CIP:192.88.158.2; IPV:NLI; CTRY:US; EFV:NLI; SFV:NSPM; SFS:(10009020)(6009001)(2980300002)(199003)(189002)(9170700003)(4326007)(33646002)(106466001)(105596002)(48376002)(5003940100001)(11100500001)(36756003)(86152002)(1220700001)(50226002)(50466002)(189998001)(2906002)(229853001)(92566002)(586003)(47776003)(8676002)(2876002)(19580405001)(77096005)(86362001)(81166006)(110136002)(575784001)(19580395003)(8936002)(104016004)(5008740100001)(6806005)(87936001)(2351001)(50986999)(21314002)(32563001)(414714003)(473944003); DIR:OUT; SFP:1101; SCL:1; SRVR:BN1PR0301MB0593; H:az84smr01.freescale.net; FPR:; SPF:SoftFail; MLV:nov; A:1; MX:1; PTR:InfoDomainNonexistent; LANG:en; X-Microsoft-Exchange-Diagnostics: 1; BN1BFFO11FD024; 1:E/vOB5obzx3+D/v5+viBbuLR+Rwzb7wEPO3uAXsNUoUiziuLcEFImswL1npxAL1MzJC+5g9g8dpiBA08+214dGpOrdRqMujRu+1mzgGaK/SYtZhQ1GWJpb74GP5vt0htzqpyjKsA70JQ7S394iLX05+0AAPVfyE6/dcQj9lZldJS7Etk24FKiyChwkzuCSod5QTBWqf9gBYqy8HUs5iOsauqUj51ye/1L5LICBQo8XJqHnoTPFZffprGDK6jjZ+OcIw+d/DRU4XVaMDntHmlP62WRkY2L4uMB3dgIClGlvV3Gtd21NuJDl6cAjz6DDaxjz5P3vP4NvV3/UP5whmIlq31/Pw5JeXcF2zCVl2dphSZ/yzonUicbYn7r8uloLwb/rqqK3kpuUq9JPbpFUh8VfTVVK0swkZ96cKORsxxApgbMQMrJVP2ipl3qGsO51RvOteV7yO+vK5gm+RP3EkXGTFPyoE+ohoB1XH45VMCJNkzHwyVq4Y1gsP8xeXPcuGuzFWZumaWjlL5G6vxrgnzzqf+cR6TmxXht5KfbnTp5QTNCpbMJ+vktldqVkNhJidl0XcDyXA8A89yzh2lwmrE7g== MIME-Version: 1.0 X-MS-Office365-Filtering-Correlation-Id: 20526dac-ed73-4327-d611-08d37fb7bca4 X-Microsoft-Exchange-Diagnostics: 1; BN1PR0301MB0593; 2:6j2yk7ITIZ3lR9Rip1tWNyFgU1geQ6LNkqFC8/wl7/7wG7wPXr/SheFzD/cSkDalyVGWVsrYH6KeeI1EfecRQ4Ne/11weJfoHUy/wmtn95oJ3rRH1VKe36xKsks3WZmN6y8vsqsoJBFkobFqLdTDLPyuz0JFdgA1mIBTmM+0jozoYFZmRTLigtsGPRWdieml; 3:n3ha8YziOvYUvmw8v8u45xDXFrTECUqRB8Wpp4Q6kwhCifH4peGhacCVRgQQHIPx6GkcBBkbYZMYdR5mfgFiAO0h0/jmh1/AfUa6F9E29mVO9HNiVoLVoqWv8NjKEPiW1HyUIMm0dQ3pJoew3XUbtQOqFRJpH2jf92ZF8/k+ow0Kb70MSI2e/HyGeubrUSsDmg0XJVVRJ3draQPryORrmJ+KDyKkwFF93hI2taB+L18= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BN1PR0301MB0593; X-Microsoft-Exchange-Diagnostics: 1; BN1PR0301MB0593; 25:nV2vp7N8HXss6QhnIW939t0LRk13VmjgPrfjPLVtNOXRjaCwo/fMtytoIwOWbQDvCBmRyBSoKwW80ulpcYU3IgJEml9zI6bV4PkCNzUV4UrsSDYn0sWn+FHjQO9QpMn3bNpoKc0sgbSVA0vTuRLCim+7me8MLJxn3IPTK8K5oDLa49pB8U3LPZcLUY0rzfCucNjnYFbDtPc6di+ZHSfRNEfEcGOjKaL+4XQqidsE4RgFypKBbl1y4w9ynIsrlFZFierZcsyrsJ8uGRcALy6xjqToWkvAWG3ltTGqighUebGBN2dvd0HKVj63N94ZxiILNxkBQCZocVA45G15CSejiCC7f8ajYUC59ev9MHDMdvdzuNwP6QBrSeYbWrAwsRIITjU6q8UtSt2/FVeuhoiiZRP01CENwbW3HG7A9eUNljegd9+fvF0JKwT5nvWY6aYF6vlvCXLlazcb46S4HEV6kh74hiFpyfawmJocwkeJ6VEVfj8RN3MXHNItveyIEE19Q9ZEptwjEz4YWhKgVbqiEYMRNf7OjYA0Q6gHuIlVSl0fRph653wqHpkeI9oxh3OJAsCHmhX+y8N9DQGLi6OI3jzXXnFWQCT95YubHaXeW2gGFjtsBXw8LzmYfrPgAotPbr7uB7as0uSTD7KxbzzhvN4mh6uixgXUI+TnRjXU06rpoPYmr83hPHAucP+D8/++0ru6/tz8hKg6Sksr16aXEn0rDpg2seLbyajlmfIn6pE= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(13024025)(13023025)(13018025)(13017025)(13015025)(5005006)(8121501046)(3002001)(10201501046)(6055026); SRVR:BN1PR0301MB0593; BCL:0; PCL:0; RULEID:(400006); SRVR:BN1PR0301MB0593; X-Microsoft-Exchange-Diagnostics: 1; BN1PR0301MB0593; 4:jYsggOxqMfQS3gHEDfF1OLru9ChJ1ZS+iiUygPF5DCq+wCX2fF4b/Qd/ubAGQpiW6iideX7ZUMbGEoIj4MyrFCt6CR+wkELcSJesc27pNsSOI2dE8eG/peNFbvX62lEImwQ6obIJmjTsTi+jJGg4O4mX1TVM/CFH520rFSd6SE87eNdmdd82mfkjJtMSjSyg58kdVBVgU/mHsg0+Eiy6v+ybqBqXEDTtI/G8rYlJR+sH1yzp8I4Y+2+nTeBzTeRxrP2aI/mJ9wi4bkcYBys2VdAoCq+kGjo/BotBvtDzpOiaVNusZ3EuTTZvqlVW2eZyluXEVEMuX1NxshLmghcnCm1htAN1zwcMfM916cXaHS6AXfNSHq+enR02r5lZHTq5uJKZafrDh3TcLT4AVYX7pvmgMf5CIveATs7jFvHQ80u1+ptqy8Ot/cZC2sc3JFcva3zDHlzNkNJjdlAEuXWRWFaIjpQrKhmVhXxDNMnXJoY= X-Forefront-PRVS: 094700CA91 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; BN1PR0301MB0593; 23:cxvdZa7Tg0/0MUswzGSwFPkt/URmE3ws/sA19nq?= =?us-ascii?Q?XtD9gpVH4UcR+jrOwgiar49JOSQ9oT3PFPfKGWwdxlxsAnAkC0i3fMbqzA2G?= =?us-ascii?Q?JxWFB4lnlrC7/HecbzHyTMyHa8aIfOUq7RIQJwuDZdvy38ms0qOvSK16fja9?= =?us-ascii?Q?uSB4mp8SLLRc9qKxBhoY9CuGVDydhwkUXmwLrgl53jxceZ9IQ3x9FyJ/pJ/U?= =?us-ascii?Q?FNN+aRs+IRuBUurrXT+kwLt++OprUa/EXBOzX32g0m/mDLfcMjL27paxAQ+p?= =?us-ascii?Q?n9NFow7qmQSczY13KlWPUUMjn/iBz8EGGri7/kKd0dqM+CORc/a9ESDmXNGV?= =?us-ascii?Q?BmWsF9ljNLslDUaGO630C+dK/5QEPGHG6sYkT6YJGCIja6Mk3pUUHSMY2B8e?= =?us-ascii?Q?rxwFyXq8fbpmv98uj6KQ1hTa+5pkpkHrofqGAet61X4I9K/3x7NJ9wHvo6tZ?= =?us-ascii?Q?pP5JUxFpBOxup7VkUQFJr0h2un4AL6pJxGVXduYOXM2eXg/LJVfLV8wEYXOo?= =?us-ascii?Q?jcesAWcUgOjXxRlnkO2nRfZ8mGFlbEZc4CEetlBRmcjobCj9ggqTvh+DCA1A?= =?us-ascii?Q?DFAzsvefPxotqN3iUivgw+phFktAs+cKJ6D+kV79bJj/ZfsX1q2zdeVIL7TZ?= =?us-ascii?Q?77ulTyMoSx0LU4Ysq05srgpLiHIiakZLodQWeD6bKdC3OHEZWUFL1+ipeRhj?= =?us-ascii?Q?E9a8ZgSxxQdiJGrCwwRJA26C82MlApcxGJ56RTT1zfDdYXx3WAIXcEfgJqh/?= =?us-ascii?Q?9ZhSWzE3fpvkY010zkWiw+PZdQNMoOnmrOtLBsKNueF27cEM/chZICplD3QE?= =?us-ascii?Q?YiPxuF494ZfGUgXzx3uhqLNsb2baeFYdVuTpvpzplM0FtY41lC+rClbRTsuQ?= =?us-ascii?Q?CPuCojrawTIYufxGRG207eKhT52wNXVOSQPjmelDCPZUd7paCzbjWq5E492x?= =?us-ascii?Q?XvT8Pjyh0ukazaKnCg4owXrQmEt6Nr79D/p1uKDkEeWKfjHrCjtDrO6DqLFt?= =?us-ascii?Q?IILYUldBqzBxYMcG979jQFj6WZlm5H3Wfub1cTA9DD16OYMGj4Aq3UxG8Bn1?= =?us-ascii?Q?rh32tQDfoYkCWHpyIOWfWVzskh61nzRNZDEVVAX/YWQPWaxXnxYqazAOBhU5?= =?us-ascii?Q?OPvqnsz7c9kk=3D?= X-Microsoft-Exchange-Diagnostics: 1; BN1PR0301MB0593; 5:gPHahcznwy2R5tRAdZg73wqXQrBKD6gDUGc5AissnXqqCpPePEMOtNUaDlc5Wzjt0EhPHfuS1wa5WXxvhM9RqOpkTUohTJGAKnGfPDw7ZSrlnRJ9C+IMmuXRRLlEM/8vGkSoqvj6WzKaIyy4ZQm13Ez93tBzQ4sjWWrZlr8Gtbk=; 24:R6VTJve1TNx8qji0BheDNH8SWW/87xBCqEtwp14HelP09trvRLzqdkFxcJoqGhdTH0NEna5FA6CbFra3XakOypVrp3xs0+sbldnfGyVLDVs=; 7:8Cwpnwr7rV3yOQoLEOJG2c77bVY+1kAJ40PHDKlQdcK7GQqODzGvoE0wEhLQwSXOqY4mmB3+gN1/OssaWNiu+VF9BzutD1UbhuCsY7sq4oTPm+uwc2dnixGPP/SBVEvZ/Ht85dqIcJdfxZqAENlcb7GaUesbCi7PyuBXRXoRO3KtqYWlRkQZJ9rq/WpLR925 SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-MS-Exchange-CrossTenant-OriginalArrivalTime: 19 May 2016 07:32:30.7849 (UTC) X-MS-Exchange-CrossTenant-Id: 5afe0b00-7697-4969-b663-5eab37d5f47e X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=5afe0b00-7697-4969-b663-5eab37d5f47e; Ip=[192.88.158.2]; Helo=[az84smr01.freescale.net] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN1PR0301MB0593 X-Topics: patch Subject: [lng-odp] [PATCH 1/5] example: introducing l3fwd 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" From: Xuelin Shi It is a simple l3fwd, only single thread, single port works. Would be enhanced in later versions. Signed-off-by: Xuelin Shi --- example/Makefile.am | 2 +- example/l3fwd/Makefile.am | 11 ++ example/l3fwd/odp_l3fwd.c | 218 +++++++++++++++++++++++++++++++ example/l3fwd/odp_l3fwd_db.c | 299 +++++++++++++++++++++++++++++++++++++++++++ example/l3fwd/odp_l3fwd_db.h | 137 ++++++++++++++++++++ example/m4/configure.m4 | 1 + 6 files changed, 667 insertions(+), 1 deletion(-) create mode 100644 example/l3fwd/Makefile.am create mode 100644 example/l3fwd/odp_l3fwd.c create mode 100644 example/l3fwd/odp_l3fwd_db.c create mode 100644 example/l3fwd/odp_l3fwd_db.h diff --git a/example/Makefile.am b/example/Makefile.am index 7f82c4d..67e4389 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 l3fwd switch diff --git a/example/l3fwd/Makefile.am b/example/l3fwd/Makefile.am new file mode 100644 index 0000000..0ba4527 --- /dev/null +++ b/example/l3fwd/Makefile.am @@ -0,0 +1,11 @@ +include $(top_srcdir)/example/Makefile.inc + +bin_PROGRAMS = odp_l3fwd$(EXEEXT) +odp_l3fwd_LDFLAGS = $(AM_LDFLAGS) -static +odp_l3fwd_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/example + +noinst_HEADERS = \ + $(top_srcdir)/example/l3fwd/odp_l3fwd_db.h \ + $(top_srcdir)/example/example_debug.h + +dist_odp_l3fwd_SOURCES = odp_l3fwd.c odp_l3fwd_db.c diff --git a/example/l3fwd/odp_l3fwd.c b/example/l3fwd/odp_l3fwd.c new file mode 100644 index 0000000..704d33e --- /dev/null +++ b/example/l3fwd/odp_l3fwd.c @@ -0,0 +1,218 @@ +/* Copyright (c) 2016, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include +#include +#include +#include + +#include "odp_l3fwd_db.h" + +#define POOL_NUM_PKT 8192 +#define POOL_SEG_LEN 1856 +#define MAX_PKT_BURST 32 + +static const char * const route_str[] = { + "1.1.1.0/24:fm1-mac1:00.e0.0c.00.85.00", + "2.1.1.0/24:fm1-mac2:00.e0.0c.00.85.01", +}; + +struct { + odp_pktio_t if0, if1; + odp_pktin_queue_t if0in, if1in; + odp_pktout_queue_t if0out, if1out; + odph_ethaddr_t src, dst; +} global; + +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("Failed to open %s\n", name); + exit(1); + } + + odp_pktin_queue_param_init(&in_queue_param); + odp_pktout_queue_param_init(&out_queue_param); + + in_queue_param.op_mode = ODP_PKTIO_OP_MT_UNSAFE; + + if (odp_pktin_queue_config(pktio, &in_queue_param)) { + printf("Failed to config input queue for %s\n", name); + exit(1); + } + + out_queue_param.op_mode = ODP_PKTIO_OP_MT_UNSAFE; + + if (odp_pktout_queue_config(pktio, &out_queue_param)) { + printf("Failed to config output queue for %s\n", name); + exit(1); + } + + if (odp_pktin_queue(pktio, pktin, 1) != 1) { + printf("pktin queue query failed for %s\n", name); + exit(1); + } + if (odp_pktout_queue(pktio, pktout, 1) != 1) { + printf("pktout queue query failed for %s\n", name); + exit(1); + } + return pktio; +} + +static void *run_worker(void *arg ODP_UNUSED) +{ + odp_packet_t pkt_tbl[MAX_PKT_BURST]; + odp_packet_t pkt_tbl_drop[MAX_PKT_BURST]; + int pkts, i; + + if (odp_pktio_start(global.if0)) { + printf("unable to start input interface\n"); + exit(1); + } + printf("started input interface\n"); + if (odp_pktio_start(global.if1)) { + printf("unable to start output interface\n"); + exit(1); + } + printf("started output interface\n"); + printf("started all\n"); + + for (;;) { + int need_to_drop = 0; + + memset(pkt_tbl, 0, sizeof(pkt_tbl_drop)); + + pkts = odp_pktin_recv(global.if0in, pkt_tbl, MAX_PKT_BURST); + if (odp_unlikely(pkts <= 0)) + continue; + for (i = 0; i < pkts; i++) { + odp_packet_t pkt = pkt_tbl[i]; + odph_ethhdr_t *eth; + odph_ipv4hdr_t *ip; + uint32_t len; + uint32_t dst_ip; + fwd_db_entry_t *entry; + odp_pktout_queue_t outq; + + if (odp_unlikely(!odp_packet_has_l3(pkt))) { + printf("warning: packet has no ip header\n"); + return NULL; + } + + /*TODO: ipv6 need to be done */ + ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, &len); + dst_ip = odp_be_to_cpu_32(ip->dst_addr); + entry = find_fwd_db_entry(dst_ip); + if (!entry) { + pkt_tbl_drop[need_to_drop] = pkt; + need_to_drop++; + continue; + } + + if (odp_unlikely(!odp_packet_has_eth(pkt))) { + printf("warning: packet has no eth header\n"); + return NULL; + } + + eth = (odph_ethhdr_t *)odp_packet_l2_ptr(pkt, NULL); + memcpy(eth->src.addr, entry->src_mac, ODPH_ETHADDR_LEN); + memcpy(eth->dst.addr, entry->dst_mac, ODPH_ETHADDR_LEN); + odp_pktout_queue(entry->pktio, &outq, 1); + odp_pktout_send(outq, &pkt, 1); + } + + odp_packet_free_multi(pkt_tbl_drop, need_to_drop); + } + return NULL; +} + +int main(int argc, char **argv) +{ + odp_pool_t pool; + odp_pool_param_t params; + odp_cpumask_t cpumask; + odph_linux_pthread_t thd; + odp_instance_t instance; + odph_linux_thr_params_t thr_params; + size_t i; + uint8_t mac[ODPH_ETHADDR_LEN]; + + if (argc != 3) { + printf("Usage: odp_l3fwd eth0 eth1\n"); + printf("Where eth0 and eth1 are the used interfaces" + " (must have 2 of them)\n"); + exit(1); + } + + 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); + } + + /* Init l3fwd tale */ + init_fwd_db(); + + /* Add route into table */ + for (i = 0; i < sizeof(route_str) / sizeof(char *); i++) { + char buf[128]; + + snprintf(buf, 128, "%s", route_str[i]); + create_fwd_db_entry(buf); + } + + /* 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; + + pool = odp_pool_create("packet pool", ¶ms); + + if (pool == ODP_POOL_INVALID) { + printf("Error: packet pool create failed.\n"); + exit(1); + } + + global.if0 = create_pktio(argv[1], pool, &global.if0in, &global.if0out); + global.if1 = create_pktio(argv[2], pool, &global.if1in, &global.if1out); + + /* resolve route table */ + odp_pktio_mac_addr(global.if0, mac, ODPH_ETHADDR_LEN); + resolve_fwd_db(argv[1], global.if0, mac); + odp_pktio_mac_addr(global.if1, mac, ODPH_ETHADDR_LEN); + resolve_fwd_db(argv[2], global.if1, mac); + + odp_cpumask_default_worker(&cpumask, 1); + + memset(&thr_params, 0, sizeof(thr_params)); + thr_params.start = run_worker; + thr_params.arg = NULL; + thr_params.thr_type = ODP_THREAD_WORKER; + thr_params.instance = instance; + + odph_linux_pthread_create(&thd, &cpumask, &thr_params); + odph_linux_pthread_join(&thd, 1); + return 0; +} diff --git a/example/l3fwd/odp_l3fwd_db.c b/example/l3fwd/odp_l3fwd_db.c new file mode 100644 index 0000000..2140cca --- /dev/null +++ b/example/l3fwd/odp_l3fwd_db.c @@ -0,0 +1,299 @@ +/* Copyright (c) 2014, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* enable strtok */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include + +#include + +#include + +#include + +/** + * Compute hash value from a flow + */ +static inline +uint64_t odp_l3fwd_calc_hash(ipv4_tuple5_t *flow) +{ + uint64_t l4_ports = 0; + ipv4_tuple5_t key; + + key = *flow; + + key.dst_ip += JHASH_GOLDEN_RATIO; + ODP_BJ3_MIX(key.src_ip, key.dst_ip, l4_ports); + + return l4_ports; +} + +/** + * Parse text string representing an IPv4 address or subnet + * + * String is of the format "XXX.XXX.XXX.XXX(/W)" where + * "XXX" is decimal value and "/W" is optional subnet length + * + * @param ipaddress Pointer to IP address/subnet string to convert + * @param addr Pointer to return IPv4 address + * @param mask Pointer (optional) to return IPv4 mask + * + * @return 0 if successful else -1 + */ +static inline +int parse_ipv4_string(char *ipaddress, uint32_t *addr, uint32_t *mask) +{ + int b[4]; + int qualifier = 32; + int converted; + + if (strchr(ipaddress, '/')) { + converted = sscanf(ipaddress, "%d.%d.%d.%d/%d", + &b[3], &b[2], &b[1], &b[0], + &qualifier); + if (5 != converted) + return -1; + } else { + converted = sscanf(ipaddress, "%d.%d.%d.%d", + &b[3], &b[2], &b[1], &b[0]); + if (4 != converted) + return -1; + } + + if ((b[0] > 255) || (b[1] > 255) || (b[2] > 255) || (b[3] > 255)) + return -1; + if (!qualifier || (qualifier > 32)) + return -1; + + *addr = b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24; + if (mask) + *mask = ~(0xFFFFFFFF & ((1ULL << (32 - qualifier)) - 1)); + + return 0; +} + +/** + * Parse text string representing a MAC address into byte araray + * + * String is of the format "XX.XX.XX.XX.XX.XX" where XX is hexadecimal + * + * @param macaddress Pointer to MAC address string to convert + * @param mac Pointer to MAC address byte array to populate + * + * @return 0 if successful else -1 + */ +static inline +int parse_mac_string(char *macaddress, uint8_t *mac) +{ + int macwords[ODPH_ETHADDR_LEN]; + int converted; + + converted = sscanf(macaddress, + "%x.%x.%x.%x.%x.%x", + &macwords[0], &macwords[1], &macwords[2], + &macwords[3], &macwords[4], &macwords[5]); + if (6 != converted) + return -1; + + mac[0] = macwords[0]; + mac[1] = macwords[1]; + mac[2] = macwords[2]; + mac[3] = macwords[3]; + mac[4] = macwords[4]; + mac[5] = macwords[5]; + + return 0; +} + +/** + * Generate text string representing IPv4 range/subnet, output + * in "XXX.XXX.XXX.XXX/W" format + * + * @param b Pointer to buffer to store string + * @param range Pointer to IPv4 address range + * + * @return Pointer to supplied buffer + */ +static inline +char *ipv4_subnet_str(char *b, ip_addr_range_t *range) +{ + int idx; + int len; + + for (idx = 0; idx < 32; idx++) + if (range->mask & (1 << idx)) + break; + len = 32 - idx; + + sprintf(b, "%03d.%03d.%03d.%03d/%d", + 0xFF & ((range->addr) >> 24), + 0xFF & ((range->addr) >> 16), + 0xFF & ((range->addr) >> 8), + 0xFF & ((range->addr) >> 0), + len); + return b; +} + +/** + * Generate text string representing MAC address + * + * @param b Pointer to buffer to store string + * @param mac Pointer to MAC address + * + * @return Pointer to supplied buffer + */ +static inline +char *mac_addr_str(char *b, uint8_t *mac) +{ + sprintf(b, "%02X.%02X.%02X.%02X.%02X.%02X", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return b; +} + +/** Global pointer to fwd db */ +fwd_db_t *fwd_db; + +void init_fwd_db(void) +{ + odp_shm_t shm; + + shm = odp_shm_reserve("shm_fwd_db", + sizeof(fwd_db_t), + ODP_CACHE_LINE_SIZE, + 0); + + fwd_db = odp_shm_addr(shm); + + if (fwd_db == NULL) { + EXAMPLE_ERR("Error: shared mem alloc failed.\n"); + exit(EXIT_FAILURE); + } + memset(fwd_db, 0, sizeof(*fwd_db)); +} + +int create_fwd_db_entry(char *input) +{ + int pos = 0; + char *local; + char *str; + char *save; + char *token; + fwd_db_entry_t *entry = &fwd_db->array[fwd_db->index]; + + /* Verify we haven't run out of space */ + if (MAX_DB <= fwd_db->index) + return -1; + + /* Make a local copy */ + local = malloc(strlen(input) + 1); + if (NULL == local) + return -1; + strcpy(local, input); + + /* Setup for using "strtok_r" to search input string */ + str = local; + save = NULL; + + /* Parse tokens separated by ':' */ + while (NULL != (token = strtok_r(str, ":", &save))) { + str = NULL; /* reset str for subsequent strtok_r calls */ + + /* Parse token based on its position */ + switch (pos) { + case 0: + parse_ipv4_string(token, + &entry->subnet.addr, + &entry->subnet.mask); + break; + case 1: + strncpy(entry->oif, token, OIF_LEN - 1); + entry->oif[OIF_LEN - 1] = 0; + break; + case 2: + parse_mac_string(token, entry->dst_mac); + break; + default: + printf("ERROR: extra token \"%s\" at position %d\n", + token, pos); + break; + } + + /* Advance to next position */ + pos++; + } + + /* Verify we parsed exactly the number of tokens we expected */ + if (3 != pos) { + printf("ERROR: \"%s\" contains %d tokens, expected 3\n", + input, + pos); + free(local); + return -1; + } + + /* Reset pktio to invalid */ + entry->pktio = ODP_PKTIO_INVALID; + + /* Add route to the list */ + fwd_db->index++; + entry->next = fwd_db->list; + fwd_db->list = entry; + + free(local); + return 0; +} + +void resolve_fwd_db(char *intf, odp_pktio_t pktio, uint8_t *mac) +{ + fwd_db_entry_t *entry; + + /* Walk the list and attempt to set output and MAC */ + for (entry = fwd_db->list; NULL != entry; entry = entry->next) { + if (strcmp(intf, entry->oif)) + continue; + + entry->pktio = pktio; + memcpy(entry->src_mac, mac, ODPH_ETHADDR_LEN); + } +} + +void dump_fwd_db_entry(fwd_db_entry_t *entry) +{ + char subnet_str[MAX_STRING]; + char mac_str[MAX_STRING]; + + printf(" %s %s %s\n", + ipv4_subnet_str(subnet_str, &entry->subnet), + entry->oif, + mac_addr_str(mac_str, entry->dst_mac)); +} + +void dump_fwd_db(void) +{ + fwd_db_entry_t *entry; + + printf("\n" + "Routing table\n" + "-------------\n"); + + for (entry = fwd_db->list; NULL != entry; entry = entry->next) + dump_fwd_db_entry(entry); +} + +fwd_db_entry_t *find_fwd_db_entry(uint32_t dst_ip) +{ + fwd_db_entry_t *entry; + + for (entry = fwd_db->list; NULL != entry; entry = entry->next) + if (entry->subnet.addr == (dst_ip & entry->subnet.mask)) + break; + + return entry; +} diff --git a/example/l3fwd/odp_l3fwd_db.h b/example/l3fwd/odp_l3fwd_db.h new file mode 100644 index 0000000..bd27b2a --- /dev/null +++ b/example/l3fwd/odp_l3fwd_db.h @@ -0,0 +1,137 @@ +/* Copyright (c) 2014, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ODP_L3FWD_DB_H_ +#define ODP_L3FWD_DB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define OIF_LEN 32 +#define MAX_DB 32 +#define MAX_STRING 32 + +/** + * Default number of flows + */ +#define ODP_MAX_FLOW_COUNT 100000 + +/** + * Default Hash bucket number + */ +#define ODP_MAX_BUCKET_COUNT (ODP_MAX_FLOW_COUNT / 8) + +/** + * Hash calculation utility + */ +#define JHASH_GOLDEN_RATIO 0x9e3779b9 +#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) +#define ODP_BJ3_MIX(a, b, c) \ +{ \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c, 16); c += b; \ + b -= a; b ^= rot(a, 19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} + +/** + * IP address range (subnet) + */ +typedef struct ip_addr_range_s { + uint32_t addr; /**< IP address */ + uint32_t mask; /**< mask, 1 indicates bits are valid */ +} ip_addr_range_t; + +/** + * TCP/UDP flow + */ +typedef struct ipv4_tuple5_s { + uint32_t src_ip; + uint32_t dst_ip; + uint16_t src_port; + uint16_t dst_port; + uint8_t proto; +} ipv4_tuple5_t; + +/** + * Forwarding data base entry + */ +typedef struct fwd_db_entry_s { + struct fwd_db_entry_s *next; /**< Next entry on list */ + char oif[OIF_LEN]; /**< Output interface name */ + odp_pktio_t pktio; /**< Output transmit port */ + uint8_t src_mac[ODPH_ETHADDR_LEN]; /**< Output source MAC */ + uint8_t dst_mac[ODPH_ETHADDR_LEN]; /**< Output destination MAC */ + ip_addr_range_t subnet; /**< Subnet for this router */ +} fwd_db_entry_t; + +/** + * Forwarding data base hash structure + */ +typedef struct fwd_db_s { + uint32_t index; /**< Next available entry */ + fwd_db_entry_t *list; /**< List of active routes */ + fwd_db_entry_t array[MAX_DB]; /**< Entry storage */ +} fwd_db_t; + +/** Global pointer to fwd db */ +extern fwd_db_t *fwd_db; + +/** Initialize FWD DB */ +void init_fwd_db(void); + +/** + * Create a forwarding database entry + * + * String is of the format "SubNet:Intf:NextHopMAC" + * + * @param input Pointer to string describing route + * + * @return 0 if successful else -1 + */ +int create_fwd_db_entry(char *input); + +/** + * Scan FWD DB entries and resolve output queue and source MAC address + * + * @param intf Interface name string + * @param pktio Output port for packet transmit + * @param mac MAC address of this interface + */ +void resolve_fwd_db(char *intf, odp_pktio_t pktio, uint8_t *mac); + +/** + * Display one fowarding database entry + * + * @param entry Pointer to entry to display + */ +void dump_fwd_db_entry(fwd_db_entry_t *entry); + +/** + * Display the forwarding database + */ +void dump_fwd_db(void); + +/** + * Find a matching forwarding database entry + * + * @param dst_ip Destination IPv4 address + * + * @return pointer to forwarding DB entry else NULL + */ +fwd_db_entry_t *find_fwd_db_entry(uint32_t dst_ip); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/example/m4/configure.m4 b/example/m4/configure.m4 index 9731d81..7868574 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/l3fwd/Makefile example/switch/Makefile])