From patchwork Fri Mar 9 21:02:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: William Tu X-Patchwork-Id: 883997 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="hVuH3niu"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3zyfwc1ptkz9sYd for ; Sat, 10 Mar 2018 08:02:56 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 35F6111E1; Fri, 9 Mar 2018 21:02:52 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id E2A501198 for ; Fri, 9 Mar 2018 21:02:50 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f67.google.com (mail-pg0-f67.google.com [74.125.83.67]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id A4057624 for ; Fri, 9 Mar 2018 21:02:50 +0000 (UTC) Received: by mail-pg0-f67.google.com with SMTP id i14so4016585pgv.3 for ; Fri, 09 Mar 2018 13:02:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=Yv5fH2Y9xYsalzQ+tevE6a9v7gtGgMP8ozeKl9kApms=; b=hVuH3niu46R4E9rGlexSXRI8utscSyoEPwcv6Q4PmChlwZWKNBldt/h1qciB6344p7 mvt8AVT2A0+lcky4XIVVzuNscCb4ywXd3J6GRNPtwmCyqFIpisznomVtwnpPTPzu9VQ+ MbBaqdSab1MKMFRdGBYS3v6jYO6/u6gfq8ZCHdB1Pla5vhdE13l/uTFXtCsWV7vwI/7V lEtN8b3BN7R4RRiFB6NgJzqQ/VffdknLq4R+gkfONk2j1ceA7vhIuUIffpA0LdlgG/ub Ki+FumLFEqtfP9dWw3IazTemYtae6CbEnOLvX2EVOvQ/ASEOt335ukQuuD+tmBJhVaGh eUBg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=Yv5fH2Y9xYsalzQ+tevE6a9v7gtGgMP8ozeKl9kApms=; b=hV2l3A1NtSwaHC5eI7LMZ3dz0WAfDrRQisQowEsrJ9msDhCAp90M9g83C6mz6uIV5f 7jWLC71pO8r2JxnsJauGhCyxOarm2Tf7BQgcU5/V8MvMqe9DQJJA3hV8y3R/9d/SoXCa UffQ5M8IkqsteGr1sVsCqYC5w+SqB5J1/JaU+UtV5hZJbMIW+gNch5o6hs0pT2LLlEzT XeVYj0WAf7Bq89RLu4cxRmWgkimJ0peXNHp+97pjoIP6R99UgNvkWnSAJUM/J/OabYNp c+0fBNVdZ00bBUR8mQLOj2ncVVbAnRqiECjv5Y235IO/MW0vIMRN72yHQUYMZ4GsjvTB r+lQ== X-Gm-Message-State: APf1xPATl2AY/FZiZYuB7RBK4Do2p1crjMjFhV+oT/nvf8eD7d3/xLIL Zh9lMn0bp+tnKjf9qhHhlAq4/XKJ X-Google-Smtp-Source: AG47ELsII4CtAlxJCV+STwCkPMncUjRjYJthnfC0M2k43HQKexrubHx6UyT/i5HDD0Vm8N5dKKd1QA== X-Received: by 10.101.65.5 with SMTP id w5mr25449873pgp.214.1520629370106; Fri, 09 Mar 2018 13:02:50 -0800 (PST) Received: from sc9-mailhost2.vmware.com ([24.5.191.4]) by smtp.gmail.com with ESMTPSA id x4sm4679144pfb.46.2018.03.09.13.02.49 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 09 Mar 2018 13:02:49 -0800 (PST) From: William Tu To: dev@openvswitch.org Date: Fri, 9 Mar 2018 13:02:21 -0800 Message-Id: <1520629345-130136-2-git-send-email-u9012063@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1520629345-130136-1-git-send-email-u9012063@gmail.com> References: <1520629345-130136-1-git-send-email-u9012063@gmail.com> X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH 1/5] system-common-macros: add tunnel-args support. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Add new tunnel-args for creating ipv6 tunnel through iproute2. Signed-off-by: William Tu --- tests/system-common-macros.at | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/system-common-macros.at b/tests/system-common-macros.at index f7d4adb947a0..d2a9b59e9684 100644 --- a/tests/system-common-macros.at +++ b/tests/system-common-macros.at @@ -179,12 +179,13 @@ m4_define([ADD_OVS_TUNNEL], ] ) -# ADD_OVS_TUNNEL6([type], [bridge], [port], [remote-addr], [overlay-addr]) +# ADD_OVS_TUNNEL6([type], [bridge], [port], [remote-addr], [overlay-addr], +# [tunnel-args]) # # Same as ADD_OVS_TUNNEL, but drops MTU enough for the IPv6 underlay. # m4_define([ADD_OVS_TUNNEL6], - [ADD_OVS_TUNNEL([$1], [$2], [$3], [$4], [$5]) + [ADD_OVS_TUNNEL([$1], [$2], [$3], [$4], [$5], [$6]) AT_CHECK([ip link set dev $2 mtu 1430]) ] ) From patchwork Fri Mar 9 21:02:22 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: William Tu X-Patchwork-Id: 883999 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="UiL1dC4Z"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3zyfy41P9Sz9sYg for ; Sat, 10 Mar 2018 08:04:11 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id AD6CB11F2; Fri, 9 Mar 2018 21:02:55 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 2C2CF1198 for ; Fri, 9 Mar 2018 21:02:52 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf0-f194.google.com (mail-pf0-f194.google.com [209.85.192.194]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id E45F4620 for ; Fri, 9 Mar 2018 21:02:51 +0000 (UTC) Received: by mail-pf0-f194.google.com with SMTP id 17so1764417pfw.11 for ; Fri, 09 Mar 2018 13:02:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=MXaDBviixJUeELVDFfR+MXVR2A1fch3wGLjHw5aY/xM=; b=UiL1dC4ZsK7dXJSBckN9QOuXNvBm27mqzTe4ZCIJG6RfkR76whOWP1l433X0TxC9y4 MTcSRPX1ykM5cdZZFIfXNpWpCNpLjgsYPYiR5bjP1ZzvE3heoK/gjWBOSCyLsnJCIQMY Eqalo9NYWwioo6sJXX+m4D542bviKh35Zrkh+/nBZl8gjTS4FFXnr7hOA5Z/FHqkV5zc nPtEZEsSyI+aDf7v2Tyd7OwOBZjKhhWfpqqpLawa0ORKLERDtqVVh1NZHKi+GXcHqlA5 nheiaQy1WIwlHKGrarBuncDHpuC0pBX9NMik1E3EvezXGwZMl8yim0hilCdaRXja+AxY 6sXA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=MXaDBviixJUeELVDFfR+MXVR2A1fch3wGLjHw5aY/xM=; b=Nr3Jm8Va2VlRDMVYCgnuyHgagkq/wBG1rWQpC/u0nt7KKFc6xSu/ugAHVWScoGNQVB O6GHtlrbm05i9sWznX/wLJAhvZG28fpwZfL9fq1l9kscrJ66WDI0qxi1oWyKMvWDQ1xp PoSOwv3fK3A+SS7SWhy8j7avn3QgRkjepZ1IlEMWQ3szWTCUsYtlb6PgHtX/14lo0TiO p7KyCfnobFyvL9+ve4BgeeMjtZB78sq3WL0DmPpP5CVenLShb3x68FD9JlY7uLaWzv6q XXnAw4/s9JqrBkDG6wX5DHYVLPUreKcbzhlMt06wPOSBT9tynjhgZoYRpl4GhKHXdyNi xUzw== X-Gm-Message-State: AElRT7EhBSr5p+0tdStdoXrCnSLIrTjBSBgPmCxXERaMhj+TdzYKD/zE G2dKRgEi6bUyBBtd1L2rTqUOyvOh X-Google-Smtp-Source: AG47ELtdDE1wTe4e89TlZFTtTk2qEwxGnwVpY9qqHOEI8uaM7TETN0FD5ddS9Yq/8pRgKgN8FmO/wg== X-Received: by 10.101.67.73 with SMTP id k9mr2868075pgq.244.1520629371365; Fri, 09 Mar 2018 13:02:51 -0800 (PST) Received: from sc9-mailhost2.vmware.com ([24.5.191.4]) by smtp.gmail.com with ESMTPSA id x4sm4679144pfb.46.2018.03.09.13.02.50 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 09 Mar 2018 13:02:50 -0800 (PST) From: William Tu To: dev@openvswitch.org Date: Fri, 9 Mar 2018 13:02:22 -0800 Message-Id: <1520629345-130136-3-git-send-email-u9012063@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1520629345-130136-1-git-send-email-u9012063@gmail.com> References: <1520629345-130136-1-git-send-email-u9012063@gmail.com> X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH 2/5] userspace: return correct ipv6 header len. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org The ipv6 header len might have extension header, but current code simply returns fixed ipv6 header length 40-byte. Signed-off-by: William Tu --- lib/netdev-native-tnl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c index fb5eab033758..c3e698d2e72b 100644 --- a/lib/netdev-native-tnl.c +++ b/lib/netdev-native-tnl.c @@ -123,7 +123,7 @@ netdev_tnl_ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl, tnl->ip_tos = ntohl(tc_flow) >> 20; tnl->ip_ttl = ip6->ip6_hlim; - *hlen += IPV6_HEADER_LEN; + *hlen += packet->l4_ofs - packet->l3_ofs; } else { VLOG_WARN_RL(&err_rl, "ipv4 packet has invalid version (%d)", From patchwork Fri Mar 9 21:02:23 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: William Tu X-Patchwork-Id: 884000 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="TLYzzaVc"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3zyfyk0ydnz9sYd for ; Sat, 10 Mar 2018 08:04:46 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 92D8C11E7; Fri, 9 Mar 2018 21:02:56 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 62F4311E8 for ; Fri, 9 Mar 2018 21:02:53 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f68.google.com (mail-pg0-f68.google.com [74.125.83.68]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 10AE1620 for ; Fri, 9 Mar 2018 21:02:52 +0000 (UTC) Received: by mail-pg0-f68.google.com with SMTP id e3so4007129pga.6 for ; Fri, 09 Mar 2018 13:02:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=e8lRi6q973bJKakj+7D0YcIK4OPSfjhFfYogvi8UhH0=; b=TLYzzaVcybmJWLTka7215yn0GCeQCv3k8/3scjt5Nx+gD4otfZfVEurrz7tBD2SrkU ZKjxlG7kra/ZGgPpQInS2r2km9SDpGRpY3+Y8TpeQiWx6HMt4c/fIgs3PHePeJiCDVVj 6W9kwkS8O1i08i7HA22807URyMGp3BUHHy5+tSoq0ZlAC2UorwVwvSMp+nprWNntYDeg 2YN2t1bs3zDRfoDV1YCYK4qCYdkaD2IH8w2BAPfdlUz48rT/J52VqrjU05RxTqZVOP3g QF+VbldxEJs7EJMH7Lx61imd9Imicq0jaGB178CgF7w+gylrts5JYq/XZHEpVmLQU7ka 0S/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=e8lRi6q973bJKakj+7D0YcIK4OPSfjhFfYogvi8UhH0=; b=FOW6cW1OyO8zkCv7w03S5WKvbvcUAtoMX2blaZxa00s7DcOLhPJwFxgwP1yv1HjRMF DtQ1TtocUUKjfnWSPVlp0eGRSvMiR9LAU1NqriFeZxD8k/DTNOt3xN/8KGYb9IgNVHhZ 6gtZ0N5ONQCFo6dlbvoXiAikwR9hZ0MeQ+uYaMtM1KAnsGwv46fXwnpQSLtSNavXAz1F lLH79DNPiv/KoVugChkKXvEbhq3QfhH0TIJjYrpmsqOeO30zuFXVJh5ffrDNYzLgwliW lVqs2Ki0NlptJULkmZZYLWITZlj4vZujRoM78uHeKhAoMBAwybXHXyU9IdLwS+0j1ZhT hi5Q== X-Gm-Message-State: APf1xPACIrq6H58cDityqnYQbZGU4DyHDVKABeFzYN4s23nkzsqioXco imGr1kSGRyCZ3zXi3+gHZY7vvCQm X-Google-Smtp-Source: AG47ELvKRbiIL34VrCLjF8jL8KH/RiAvbW4q7VpTFEqxpwnQpM56yN33rXID+O9v31O1/vIvUe3eZw== X-Received: by 10.101.85.71 with SMTP id t7mr25286924pgr.386.1520629372451; Fri, 09 Mar 2018 13:02:52 -0800 (PST) Received: from sc9-mailhost2.vmware.com ([24.5.191.4]) by smtp.gmail.com with ESMTPSA id x4sm4679144pfb.46.2018.03.09.13.02.51 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 09 Mar 2018 13:02:51 -0800 (PST) From: William Tu To: dev@openvswitch.org Date: Fri, 9 Mar 2018 13:02:23 -0800 Message-Id: <1520629345-130136-4-git-send-email-u9012063@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1520629345-130136-1-git-send-email-u9012063@gmail.com> References: <1520629345-130136-1-git-send-email-u9012063@gmail.com> X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH 3/5] netdev-native-tnl: refactor the tunnel push header. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org The patch adds additional 'struct netdev *' to the native tunnel's push_header() interface. This is used for later GRE sequence number support. Signed-off-by: William Tu --- lib/netdev-native-tnl.c | 6 ++++-- lib/netdev-native-tnl.h | 6 ++++-- lib/netdev-provider.h | 3 ++- lib/netdev.c | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c index c3e698d2e72b..5eb3d22cdb2e 100644 --- a/lib/netdev-native-tnl.c +++ b/lib/netdev-native-tnl.c @@ -215,7 +215,8 @@ udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl, void -netdev_tnl_push_udp_header(struct dp_packet *packet, +netdev_tnl_push_udp_header(const struct netdev *netdev OVS_UNUSED, + struct dp_packet *packet, const struct ovs_action_push_tnl *data) { struct udp_header *udp; @@ -435,7 +436,8 @@ err: } void -netdev_gre_push_header(struct dp_packet *packet, +netdev_gre_push_header(const struct netdev *netdev OVS_UNUSED, + struct dp_packet *packet, const struct ovs_action_push_tnl *data) { struct gre_base_hdr *greh; diff --git a/lib/netdev-native-tnl.h b/lib/netdev-native-tnl.h index a912ce916dfc..5012b2dbac9a 100644 --- a/lib/netdev-native-tnl.h +++ b/lib/netdev-native-tnl.h @@ -34,13 +34,15 @@ netdev_gre_build_header(const struct netdev *netdev, const struct netdev_tnl_build_header_params *params); void -netdev_gre_push_header(struct dp_packet *packet, +netdev_gre_push_header(const struct netdev *netdev, + struct dp_packet *packet, const struct ovs_action_push_tnl *data); struct dp_packet * netdev_gre_pop_header(struct dp_packet *packet); void -netdev_tnl_push_udp_header(struct dp_packet *packet, +netdev_tnl_push_udp_header(const struct netdev *netdev, + struct dp_packet *packet, const struct ovs_action_push_tnl *data); int netdev_geneve_build_header(const struct netdev *netdev, diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h index 25bd671c1382..e63257107ff4 100644 --- a/lib/netdev-provider.h +++ b/lib/netdev-provider.h @@ -314,7 +314,8 @@ struct netdev_class { * flow. Push header is called for packet to build header specific to * a packet on actual transmit. It uses partial header build by * build_header() which is passed as data. */ - void (*push_header)(struct dp_packet *packet, + void (*push_header)(const struct netdev *, + struct dp_packet *packet, const struct ovs_action_push_tnl *data); /* Pop tunnel header from packet, build tunnel metadata and resize packet diff --git a/lib/netdev.c b/lib/netdev.c index 5a97ce53eb7a..1a23a170dcd5 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -855,7 +855,7 @@ netdev_push_header(const struct netdev *netdev, { struct dp_packet *packet; DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { - netdev->netdev_class->push_header(packet, data); + netdev->netdev_class->push_header(netdev, packet, data); pkt_metadata_init(&packet->md, data->out_port); } From patchwork Fri Mar 9 21:02:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: William Tu X-Patchwork-Id: 884001 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="qL3///M9"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3zyfzM4MbBz9sYd for ; Sat, 10 Mar 2018 08:05:19 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 72C9911F4; Fri, 9 Mar 2018 21:02:57 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 1C42111E6 for ; Fri, 9 Mar 2018 21:02:55 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f65.google.com (mail-pg0-f65.google.com [74.125.83.65]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 8C16C620 for ; Fri, 9 Mar 2018 21:02:54 +0000 (UTC) Received: by mail-pg0-f65.google.com with SMTP id s15so1375586pgv.8 for ; Fri, 09 Mar 2018 13:02:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=q/xxU7kpW7pDjosTkUY4OB6kfzXSr+gp+AQR7zwUCgw=; b=qL3///M9C7LlaN4mQhlFBbYMcICSLhhd4WVVQqs6ZKLS5GHVisJrnZxKlv8G03W70x rZPw+BQRikgNa8x+WyNCKgEwnzE/Qg71Nu6RxYATp5NqMZpL5VBSsv9Zz3o0kPj1S7M1 Dggrw2RzJqabnq3Tsg8yV483LRGAdQIq27cnx6fC2CXV0Y7HEiUTcgO0yRGUczJAh2XF RltMRLpnynsyUT4BNpx2JeobeHrkiN5DS5E0w8MMEnfctg7Z3LNXh6SkFkmDNiYj3GNg oRGMG0k7PArZrNeW/W2h9zDQkcBvLeeakVjJyknfiO56oB4ftTynMrfNHYMe3ae3Kfo5 kfGg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=q/xxU7kpW7pDjosTkUY4OB6kfzXSr+gp+AQR7zwUCgw=; b=IGj7Ma1l8NlXU+dK2W7Y5KxyCbJq94df0IZvMIxSTPuM0FrdeXlCEVjSBECXUd+Cds dcZCdcKefunj5QAj0zCO6K/PhIjDVnIpLzmOINupqaz8sElb/G+QhaeN0R4CBtZ2wtpW tL0T55JZ4bljiC4e7EMcDYOlchVsxnKFECqeVdAhy8j8eAqe+OPLZ4GvHZbv2KN9hLjZ b5KibDIbZPut5Pu4odaidzQ8rEthcIH1J5TxprCnXSNLHxR9cxSyY/4PfkuwjwwRrh8b fvVq85B3lQW1h2EKCToI9xhf3dLWYxO971am9DYzgS4pBGXQnvNv96yfkLYSTaePqAmz fh6A== X-Gm-Message-State: APf1xPDq0VmEXv4pHiPWYeID+/EYCsr0h9KbqQHvC0ag2IEU/ctSQH3s vphJaKrVzckc+upYWThy3GuVsXpc X-Google-Smtp-Source: AG47ELuoKVWKA/LMUeogWpVhblxLJkz1ZSh2zh4+lFw/F4biaswQlvg4xfs3SKPjoSFX+BFOqO/1jA== X-Received: by 10.99.124.14 with SMTP id x14mr25313562pgc.290.1520629373568; Fri, 09 Mar 2018 13:02:53 -0800 (PST) Received: from sc9-mailhost2.vmware.com ([24.5.191.4]) by smtp.gmail.com with ESMTPSA id x4sm4679144pfb.46.2018.03.09.13.02.52 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 09 Mar 2018 13:02:53 -0800 (PST) From: William Tu To: dev@openvswitch.org Date: Fri, 9 Mar 2018 13:02:24 -0800 Message-Id: <1520629345-130136-5-git-send-email-u9012063@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1520629345-130136-1-git-send-email-u9012063@gmail.com> References: <1520629345-130136-1-git-send-email-u9012063@gmail.com> X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH 4/5] userspace: add gre sequence number support. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org The patch adds support for gre sequence number. Default is disable. When enable with 'options:seq=true', the outgoing gre packet will have its sequence number incremented by one. Signed-off-by: William Tu --- lib/netdev-native-tnl.c | 18 +++++++++++++++++- lib/netdev-vport.c | 11 ++++++++++- lib/netdev.h | 3 +++ tests/tunnel-push-pop.at | 8 ++++---- vswitchd/vswitch.xml | 7 +++++++ 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c index 5eb3d22cdb2e..288930a59529 100644 --- a/lib/netdev-native-tnl.c +++ b/lib/netdev-native-tnl.c @@ -436,10 +436,12 @@ err: } void -netdev_gre_push_header(const struct netdev *netdev OVS_UNUSED, +netdev_gre_push_header(const struct netdev *netdev, struct dp_packet *packet, const struct ovs_action_push_tnl *data) { + struct netdev_vport *dev = netdev_vport_cast(netdev); + struct netdev_tunnel_config *tnl_cfg; struct gre_base_hdr *greh; int ip_tot_size; @@ -449,6 +451,14 @@ netdev_gre_push_header(const struct netdev *netdev OVS_UNUSED, ovs_be16 *csum_opt = (ovs_be16 *) (greh + 1); *csum_opt = csum(greh, ip_tot_size); } + + if (greh->flags & htons(GRE_SEQ)) { + /* Last 4 byte is GRE seqno */ + int seq_ofs = gre_header_len(greh->flags) - 4; + ovs_be32 *seq_opt = (ovs_be32 *)((char *)greh + seq_ofs); + tnl_cfg = &dev->tnl_cfg; + *seq_opt = htonl(tnl_cfg->seqno++); + } } int @@ -491,6 +501,12 @@ netdev_gre_build_header(const struct netdev *netdev, options++; } + if (tnl_cfg->set_seq) { + greh->flags |= htons(GRE_SEQ); + /* seqno is updated at push header */ + options++; + } + ovs_mutex_unlock(&dev->mutex); hlen = (uint8_t *) options - (uint8_t *) greh; diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 52aa12d79933..cc50aa5efdd6 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -428,7 +428,7 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp) const char *name = netdev_get_name(dev_); const char *type = netdev_get_type(dev_); struct ds errors = DS_EMPTY_INITIALIZER; - bool needs_dst_port, has_csum; + bool needs_dst_port, has_csum, has_seq; uint16_t dst_proto = 0, src_proto = 0; struct netdev_tunnel_config tnl_cfg; struct smap_node *node; @@ -436,6 +436,7 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp) has_csum = strstr(type, "gre") || strstr(type, "geneve") || strstr(type, "stt") || strstr(type, "vxlan"); + has_seq = strstr(type, "gre"); memset(&tnl_cfg, 0, sizeof tnl_cfg); /* Add a default destination port for tunnel ports if none specified. */ @@ -506,6 +507,10 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp) if (!strcmp(node->value, "true")) { tnl_cfg.csum = true; } + } else if (!strcmp(node->key, "seq") && has_seq) { + if (!strcmp(node->value, "true")) { + tnl_cfg.set_seq = true; + } } else if (!strcmp(node->key, "df_default")) { if (!strcmp(node->value, "false")) { tnl_cfg.dont_fragment = false; @@ -709,6 +714,10 @@ get_tunnel_config(const struct netdev *dev, struct smap *args) smap_add(args, "csum", "true"); } + if (tnl_cfg.set_seq) { + smap_add(args, "seq", "true"); + } + enum tunnel_layers layers = tunnel_supported_layers(type, &tnl_cfg); if (tnl_cfg.pt_mode != default_pt_mode(layers)) { smap_add(args, "packet_type", diff --git a/lib/netdev.h b/lib/netdev.h index ff1b604b24e2..2258c0718986 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -127,6 +127,9 @@ struct netdev_tunnel_config { bool csum; bool dont_fragment; enum netdev_pt_mode pt_mode; + + bool set_seq; + uint32_t seqno; }; void netdev_run(void); diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at index cc8b1b522741..dcea2b4c5826 100644 --- a/tests/tunnel-push-pop.at +++ b/tests/tunnel-push-pop.at @@ -293,7 +293,7 @@ AT_SETUP([tunnel_push_pop - underlay bridge match]) OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 other-config:hwaddr=aa:55:aa:55:00:00]) AT_CHECK([ovs-vsctl add-br int-br -- set bridge int-br datapath_type=dummy], [0]) AT_CHECK([ovs-vsctl add-port int-br t1 -- set Interface t1 type=gre \ - options:remote_ip=1.1.2.92 options:key=456 ofport_request=3], [0]) + options:remote_ip=1.1.2.92 options:key=456 options:seq=true ofport_request=3], [0]) AT_CHECK([ovs-appctl dpif/show], [0], [dnl dummy@ovs-dummy: hit:0 missed:0 @@ -302,7 +302,7 @@ dummy@ovs-dummy: hit:0 missed:0 p0 1/1: (dummy) int-br: int-br 65534/2: (dummy-internal) - t1 3/3: (gre: key=456, remote_ip=1.1.2.92) + t1 3/3: (gre: key=456, remote_ip=1.1.2.92, seq=true) ]) AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.2.88/24], [0], [OK @@ -325,14 +325,14 @@ AT_CHECK([ovs-ofctl add-flow int-br action=3]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=17,tos=0,ttl=64,frag=no),udp(src=51283,dst=4789)'], [0], [stdout]) AT_CHECK([tail -1 stdout], [0], - [Datapath actions: tnl_push(tnl_port(3),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x2000,proto=0x6558),key=0x1c8)),out_port(100)) + [Datapath actions: tnl_push(tnl_port(3),header(size=46,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x3000,proto=0x6558),key=0x1c8,seq=0x0)),out_port(100)) ]) dnl Verify outer L2 and L3 header flow fields can be matched in the underlay bridge AT_CHECK([ovs-appctl netdev-dummy/receive int-br '50540000000a5054000000091234']) AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl) n_packets=1, n_bytes=42, priority=1,arp actions=NORMAL - n_packets=1, n_bytes=56, priority=99,ip,dl_src=aa:55:aa:55:00:00,dl_dst=f8:bc:12:44:34:b6,nw_src=1.1.2.88,nw_dst=1.1.2.92,nw_proto=47,nw_tos=0 actions=NORMAL + n_packets=1, n_bytes=60, priority=99,ip,dl_src=aa:55:aa:55:00:00,dl_dst=f8:bc:12:44:34:b6,nw_src=1.1.2.88,nw_dst=1.1.2.92,nw_proto=47,nw_tos=0 actions=NORMAL NXST_FLOW reply: ]) diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml index 0c6a43d602c7..48554c0d2243 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -2565,6 +2565,13 @@ + +

+ Optional. A 4-byte sequence number field for GRE tunnel only. + Default is disabled, set to true to enable. + Sequence number is incremented by one on each outgoing packet. +

+
From patchwork Fri Mar 9 21:02:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: William Tu X-Patchwork-Id: 884002 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="mTxKvL1s"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3zyfzw3rHCz9sYd for ; Sat, 10 Mar 2018 08:05:48 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 8B89111FA; Fri, 9 Mar 2018 21:03:01 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id E7D1011A8 for ; Fri, 9 Mar 2018 21:03:00 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf0-f194.google.com (mail-pf0-f194.google.com [209.85.192.194]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 6AB36620 for ; Fri, 9 Mar 2018 21:02:57 +0000 (UTC) Received: by mail-pf0-f194.google.com with SMTP id h11so1768791pfn.4 for ; Fri, 09 Mar 2018 13:02:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=rg9E/SpAgJkgqK+rFt9pWh1JXoubJQQTe8OHlSkjcjU=; b=mTxKvL1s5Ndy9BjOJk0U/heLIaDTzHOfKLJU7v18aNn/feV49w26LARtDZ71upNu7D l74jW7NFS0B3iA72NcEA8ioNl7ezkdJ35kx5nJhifpq1XBIzAHI81mWrxjCU6AgMuAKl k1gJkZ2V4zBn2vZUYMzhXdIwwIivg9cvKQnGli/tQHNom3wXpNN5dr1FGWGlo3oPRlF4 SFcqNmEKKS3FZv/jpl73Kwy3rhwUw0M4igHamMlT4KMLliAm+8mCcF175pR7fjfBnJEj eC9/dNmmrQW9Uk1n4qkrb8gsHD2zoAU6KmN/Gys7LT28tVuUSEJ9G2q3CRQxoUooFb+J hxxw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=rg9E/SpAgJkgqK+rFt9pWh1JXoubJQQTe8OHlSkjcjU=; b=QIT/BYQ5CenB3CjG+Cm81lF2fCj8P4KAI0b1oGkVKBhYnSI5hKhVBf6qqqdteUaGrr lUgnxKI/bxLWNKl8cTM8HN6wsua4rz6tMH0mpOOghDdOv9gFYuB0sgA02yPiposg48Si 3myJlGK1oz692oKHvt9hhmfKJJhZitpBKNYGXwWf1y1FnqzrSs6LhHkFkmBmWp6gszJ9 RUAQmUf5ls2qNvrKvvcVQVD5k5O8RPtaNWqV+SK7I+PwgM3dZSjO4Ipv+OS2bZ7C2n0Y XWuQZk2ttxZXiMDTit+OoXU/IGeRgrcFuPpariTmmyzDzmSAfaDlmMNP4owpy2eLck0X 3VTg== X-Gm-Message-State: APf1xPDkDu2Nc6skZ26CLsuTle7ceIhero0hE8GIVR5+EDSg5Qmn6Wl0 vBokUlucj8sphnbGrimIzgtAL7WC X-Google-Smtp-Source: AG47ELsLORHItY97SL4kxUMABE9OKHgQAPMjEIHiv1nzlZJYncEQDvJYQgljFVC/ANTTIdxVxoMNqw== X-Received: by 10.99.180.77 with SMTP id n13mr25180180pgu.361.1520629374869; Fri, 09 Mar 2018 13:02:54 -0800 (PST) Received: from sc9-mailhost2.vmware.com ([24.5.191.4]) by smtp.gmail.com with ESMTPSA id x4sm4679144pfb.46.2018.03.09.13.02.53 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 09 Mar 2018 13:02:54 -0800 (PST) From: William Tu To: dev@openvswitch.org Date: Fri, 9 Mar 2018 13:02:25 -0800 Message-Id: <1520629345-130136-6-git-send-email-u9012063@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1520629345-130136-1-git-send-email-u9012063@gmail.com> References: <1520629345-130136-1-git-send-email-u9012063@gmail.com> X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH 5/5] userspace: add erspan tunnel support. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org ERSPAN is a tunneling protocol based on GRE tunnel. The patch add erspan tunnel support for ovs-vswitchd with userspace datapath. Configuring erspan tunnel is similar to gre tunnel, but with additional erspan's parameters. Matching a flow on erspan's metadata is also supported, see ovs-fields for more details. Signed-off-by: William Tu --- datapath/linux/compat/include/linux/openvswitch.h | 2 + include/openvswitch/flow.h | 4 +- include/openvswitch/match.h | 12 ++ include/openvswitch/meta-flow.h | 56 +++++++ include/openvswitch/packets.h | 6 +- lib/dpif-netlink-rtnl.c | 8 + lib/dpif-netlink.c | 6 + lib/flow.c | 32 +++- lib/flow.h | 2 +- lib/match.c | 69 ++++++++- lib/meta-flow.c | 77 ++++++++++ lib/meta-flow.xml | 86 +++++++++++ lib/netdev-native-tnl.c | 172 ++++++++++++++++++++++ lib/netdev-native-tnl.h | 12 ++ lib/netdev-vport.c | 54 +++++++ lib/netdev.h | 4 + lib/nx-match.c | 13 +- lib/odp-util.c | 83 ++++++++++- lib/odp-util.h | 2 +- lib/ofp-match.c | 2 +- lib/packets.h | 126 ++++++++++++++++ lib/tnl-ports.c | 3 +- ofproto/ofproto-dpif-rid.h | 2 +- ofproto/ofproto-dpif-xlate.c | 4 +- ofproto/tunnel.c | 13 ++ tests/ofproto.at | 6 +- tests/tunnel-push-pop-ipv6.at | 118 +++++++++++++++ tests/tunnel-push-pop.at | 137 +++++++++++++++++ tests/tunnel.at | 12 ++ vswitchd/vswitch.xml | 34 +++++ 30 files changed, 1135 insertions(+), 22 deletions(-) diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h index 84ebcaf579b6..ea25b0122a99 100644 --- a/datapath/linux/compat/include/linux/openvswitch.h +++ b/datapath/linux/compat/include/linux/openvswitch.h @@ -238,6 +238,8 @@ enum ovs_vport_type { OVS_VPORT_TYPE_GENEVE, /* Geneve tunnel. */ OVS_VPORT_TYPE_LISP = 105, /* LISP tunnel */ OVS_VPORT_TYPE_STT = 106, /* STT tunnel */ + OVS_VPORT_TYPE_ERSPAN = 107, /* ERSPAN tunnel. */ + OVS_VPORT_TYPE_IP6ERSPAN = 108, /* ERSPAN tunnel. */ __OVS_VPORT_TYPE_MAX }; diff --git a/include/openvswitch/flow.h b/include/openvswitch/flow.h index cd61ffff0289..5d2cf09680f1 100644 --- a/include/openvswitch/flow.h +++ b/include/openvswitch/flow.h @@ -27,7 +27,7 @@ extern "C" { /* This sequence number should be incremented whenever anything involving flows * or the wildcarding of flows changes. This will cause build assertion * failures in places which likely need to be updated. */ -#define FLOW_WC_SEQ 40 +#define FLOW_WC_SEQ 41 /* Number of Open vSwitch extension 32-bit registers. */ #define FLOW_N_REGS 16 @@ -166,7 +166,7 @@ BUILD_ASSERT_DECL(sizeof(struct ovs_key_nsh) % sizeof(uint64_t) == 0); /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */ BUILD_ASSERT_DECL(offsetof(struct flow, igmp_group_ip4) + sizeof(uint32_t) == sizeof(struct flow_tnl) + sizeof(struct ovs_key_nsh) + 300 - && FLOW_WC_SEQ == 40); + && FLOW_WC_SEQ == 41); /* Incremental points at which flow classification may be performed in * segments. diff --git a/include/openvswitch/match.h b/include/openvswitch/match.h index 61a67de2c413..0c7f8ce7bf8d 100644 --- a/include/openvswitch/match.h +++ b/include/openvswitch/match.h @@ -109,6 +109,18 @@ void match_set_tun_gbp_id_masked(struct match *match, ovs_be16 gbp_id, ovs_be16 void match_set_tun_gbp_id(struct match *match, ovs_be16 gbp_id); void match_set_tun_gbp_flags_masked(struct match *match, uint8_t flags, uint8_t mask); void match_set_tun_gbp_flags(struct match *match, uint8_t flags); +void match_set_tun_erspan_ver(struct match *match, uint8_t ver); +void match_set_tun_erspan_ver_masked(struct match *match, uint8_t ver, + uint8_t mask); +void match_set_tun_erspan_idx(struct match *match, uint32_t idx); +void match_set_tun_erspan_idx_masked(struct match *match, uint32_t idx, + uint32_t mask); +void match_set_tun_erspan_dir(struct match *match, uint8_t dir); +void match_set_tun_erspan_dir_masked(struct match *match, uint8_t dir, + uint8_t mask); +void match_set_tun_erspan_hwid(struct match *match, uint8_t hwid); +void match_set_tun_erspan_hwid_masked(struct match *match, uint8_t hwid, + uint8_t mask); void match_set_in_port(struct match *, ofp_port_t ofp_port); void match_set_pkt_mark(struct match *, uint32_t pkt_mark); void match_set_pkt_mark_masked(struct match *, uint32_t pkt_mark, uint32_t mask); diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h index 98c9e1cb5a76..2c1be7f2ea16 100644 --- a/include/openvswitch/meta-flow.h +++ b/include/openvswitch/meta-flow.h @@ -450,6 +450,62 @@ enum OVS_PACKED_ENUM mf_field_id { */ MFF_TUN_GBP_FLAGS, + /* "tun_erspan_idx". + * + * ERSPAN index (direction/port number) + * + * Type: be32. + * Maskable: bitwise. + * Formatting: hexadecimal. + * Prerequisites: none. + * Access: read/write. + * NXM: none. + * OXM: NXOXM_ET_ERSPAN_IDX(11) since OF1.5 and v2.9. + */ + MFF_TUN_ERSPAN_IDX, + + /* "tun_erspan_ver". + * + * ERSPAN vsersion (v1 / v2) + * + * Type: u8. + * Maskable: bitwise. + * Formatting: decimal. + * Prerequisites: none. + * Access: read/write. + * NXM: none. + * OXM: NXOXM_ET_ERSPAN_VER(12) since OF1.5 and v2.9. + */ + MFF_TUN_ERSPAN_VER, + + /* "tun_erspan_dir". + * + * ERSPAN mirrored traffic's direction + * + * Type: u8. + * Maskable: bitwise. + * Formatting: decimal. + * Prerequisites: none. + * Access: read/write. + * NXM: none. + * OXM: NXOXM_ET_ERSPAN_DIR(13) since OF1.5 and v2.9. + */ + MFF_TUN_ERSPAN_DIR, + + /* "tun_erspan_hwid". + * + * ERSPAN Hardware ID + * + * Type: u8. + * Maskable: bitwise. + * Formatting: hexadecimal. + * Prerequisites: none. + * Access: read/write. + * NXM: none. + * OXM: NXOXM_ET_ERSPAN_HWID(14) since OF1.5 and v2.9. + */ + MFF_TUN_ERSPAN_HWID, + #if TUN_METADATA_NUM_OPTS == 64 /* "tun_metadata". * diff --git a/include/openvswitch/packets.h b/include/openvswitch/packets.h index fef756b72e57..7bcb9b58410c 100644 --- a/include/openvswitch/packets.h +++ b/include/openvswitch/packets.h @@ -39,7 +39,11 @@ struct flow_tnl { ovs_be16 tp_dst; ovs_be16 gbp_id; uint8_t gbp_flags; - uint8_t pad1[5]; /* Pad to 64 bits. */ + uint32_t erspan_idx; + uint8_t erspan_ver; + uint8_t erspan_dir; + uint8_t erspan_hwid; + uint8_t pad1[6]; /* Pad to 64 bits. */ struct tun_metadata metadata; }; diff --git a/lib/dpif-netlink-rtnl.c b/lib/dpif-netlink-rtnl.c index 40c456951827..648837175581 100644 --- a/lib/dpif-netlink-rtnl.c +++ b/lib/dpif-netlink-rtnl.c @@ -99,6 +99,8 @@ vport_type_to_kind(enum ovs_vport_type type, } case OVS_VPORT_TYPE_GENEVE: return "geneve"; + case OVS_VPORT_TYPE_ERSPAN: + case OVS_VPORT_TYPE_IP6ERSPAN: case OVS_VPORT_TYPE_NETDEV: case OVS_VPORT_TYPE_INTERNAL: case OVS_VPORT_TYPE_LISP: @@ -258,6 +260,8 @@ dpif_netlink_rtnl_verify(const struct netdev_tunnel_config *tnl_cfg, case OVS_VPORT_TYPE_GENEVE: err = dpif_netlink_rtnl_geneve_verify(tnl_cfg, kind, reply); break; + case OVS_VPORT_TYPE_ERSPAN: + case OVS_VPORT_TYPE_IP6ERSPAN: case OVS_VPORT_TYPE_NETDEV: case OVS_VPORT_TYPE_INTERNAL: case OVS_VPORT_TYPE_LISP: @@ -323,6 +327,8 @@ dpif_netlink_rtnl_create(const struct netdev_tunnel_config *tnl_cfg, nl_msg_put_u8(&request, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, 1); nl_msg_put_be16(&request, IFLA_GENEVE_PORT, tnl_cfg->dst_port); break; + case OVS_VPORT_TYPE_ERSPAN: + case OVS_VPORT_TYPE_IP6ERSPAN: case OVS_VPORT_TYPE_NETDEV: case OVS_VPORT_TYPE_INTERNAL: case OVS_VPORT_TYPE_LISP: @@ -434,6 +440,8 @@ dpif_netlink_rtnl_port_destroy(const char *name, const char *type) case OVS_VPORT_TYPE_GRE: case OVS_VPORT_TYPE_GENEVE: return dpif_netlink_rtnl_destroy(name); + case OVS_VPORT_TYPE_ERSPAN: + case OVS_VPORT_TYPE_IP6ERSPAN: case OVS_VPORT_TYPE_NETDEV: case OVS_VPORT_TYPE_INTERNAL: case OVS_VPORT_TYPE_LISP: diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index 8543a2bbe462..2009dcf5c366 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -786,6 +786,8 @@ get_vport_type(const struct dpif_netlink_vport *vport) case OVS_VPORT_TYPE_STT: return "stt"; + case OVS_VPORT_TYPE_ERSPAN: + case OVS_VPORT_TYPE_IP6ERSPAN: case OVS_VPORT_TYPE_UNSPEC: case __OVS_VPORT_TYPE_MAX: break; @@ -813,6 +815,10 @@ netdev_to_ovs_vport_type(const char *type) return OVS_VPORT_TYPE_VXLAN; } else if (!strcmp(type, "lisp")) { return OVS_VPORT_TYPE_LISP; + } else if (!strcmp(type, "erspan")) { + return OVS_VPORT_TYPE_ERSPAN; + } else if (!strcmp(type, "ip6erspan")) { + return OVS_VPORT_TYPE_IP6ERSPAN; } else { return OVS_VPORT_TYPE_UNSPEC; } diff --git a/lib/flow.c b/lib/flow.c index 38ff29c8cd14..82182285131d 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -126,7 +126,7 @@ struct mf_ctx { * away. Some GCC versions gave warnings on ALWAYS_INLINE, so these are * defined as macros. */ -#if (FLOW_WC_SEQ != 40) +#if (FLOW_WC_SEQ != 41) #define MINIFLOW_ASSERT(X) ovs_assert(X) BUILD_MESSAGE("FLOW_WC_SEQ changed: miniflow_extract() will have runtime " "assertions enabled. Consider updating FLOW_WC_SEQ after " @@ -1014,7 +1014,7 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata) { int i; - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41); match_init_catchall(flow_metadata); if (flow->tunnel.tun_id != htonll(0)) { @@ -1042,6 +1042,18 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata) if (flow->tunnel.gbp_flags) { match_set_tun_gbp_flags(flow_metadata, flow->tunnel.gbp_flags); } + if (flow->tunnel.erspan_ver) { + match_set_tun_erspan_ver(flow_metadata, flow->tunnel.erspan_ver); + } + if (flow->tunnel.erspan_idx) { + match_set_tun_erspan_idx(flow_metadata, flow->tunnel.erspan_idx); + } + if (flow->tunnel.erspan_dir) { + match_set_tun_erspan_dir(flow_metadata, flow->tunnel.erspan_dir); + } + if (flow->tunnel.erspan_hwid) { + match_set_tun_erspan_hwid(flow_metadata, flow->tunnel.erspan_hwid); + } tun_metadata_get_fmd(&flow->tunnel, flow_metadata); if (flow->metadata != htonll(0)) { match_set_metadata(flow_metadata, flow->metadata); @@ -1581,7 +1593,7 @@ flow_wildcards_init_for_packet(struct flow_wildcards *wc, memset(&wc->masks, 0x0, sizeof wc->masks); /* Update this function whenever struct flow changes. */ - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41); if (flow_tnl_dst_is_set(&flow->tunnel)) { if (flow->tunnel.flags & FLOW_TNL_F_KEY) { @@ -1598,6 +1610,10 @@ flow_wildcards_init_for_packet(struct flow_wildcards *wc, WC_MASK_FIELD(wc, tunnel.tp_dst); WC_MASK_FIELD(wc, tunnel.gbp_id); WC_MASK_FIELD(wc, tunnel.gbp_flags); + WC_MASK_FIELD(wc, tunnel.erspan_ver); + WC_MASK_FIELD(wc, tunnel.erspan_idx); + WC_MASK_FIELD(wc, tunnel.erspan_dir); + WC_MASK_FIELD(wc, tunnel.erspan_hwid); if (!(flow->tunnel.flags & FLOW_TNL_F_UDPIF)) { if (flow->tunnel.metadata.present.map) { @@ -1728,7 +1744,7 @@ void flow_wc_map(const struct flow *flow, struct flowmap *map) { /* Update this function whenever struct flow changes. */ - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41); flowmap_init(map); @@ -1829,7 +1845,7 @@ void flow_wildcards_clear_non_packet_fields(struct flow_wildcards *wc) { /* Update this function whenever struct flow changes. */ - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41); memset(&wc->masks.metadata, 0, sizeof wc->masks.metadata); memset(&wc->masks.regs, 0, sizeof wc->masks.regs); @@ -1973,7 +1989,7 @@ flow_wildcards_set_xxreg_mask(struct flow_wildcards *wc, int idx, uint32_t miniflow_hash_5tuple(const struct miniflow *flow, uint32_t basis) { - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41); uint32_t hash = basis; if (flow) { @@ -2020,7 +2036,7 @@ ASSERT_SEQUENTIAL(ipv6_src, ipv6_dst); uint32_t flow_hash_5tuple(const struct flow *flow, uint32_t basis) { - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41); uint32_t hash = basis; if (flow) { @@ -2609,7 +2625,7 @@ flow_push_mpls(struct flow *flow, int n, ovs_be16 mpls_eth_type, if (clear_flow_L3) { /* Clear all L3 and L4 fields and dp_hash. */ - BUILD_ASSERT(FLOW_WC_SEQ == 40); + BUILD_ASSERT(FLOW_WC_SEQ == 41); memset((char *) flow + FLOW_SEGMENT_2_ENDS_AT, 0, sizeof(struct flow) - FLOW_SEGMENT_2_ENDS_AT); flow->dp_hash = 0; diff --git a/lib/flow.h b/lib/flow.h index 770a07a62778..2b96dc9a6b5c 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -917,7 +917,7 @@ static inline void pkt_metadata_from_flow(struct pkt_metadata *md, const struct flow *flow) { /* Update this function whenever struct flow changes. */ - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41); md->recirc_id = flow->recirc_id; md->dp_hash = flow->dp_hash; diff --git a/lib/match.c b/lib/match.c index 97a5282997b0..cd2cb5d0ffe3 100644 --- a/lib/match.c +++ b/lib/match.c @@ -320,6 +320,61 @@ match_set_tun_gbp_flags(struct match *match, uint8_t flags) } void +match_set_tun_erspan_ver_masked(struct match *match, uint8_t ver, uint8_t mask) +{ + match->wc.masks.tunnel.erspan_ver = ver; + match->flow.tunnel.erspan_ver = ver & mask; +} + +void +match_set_tun_erspan_ver(struct match *match, uint8_t ver) +{ + match_set_tun_erspan_ver_masked(match, ver, UINT8_MAX); +} + +void +match_set_tun_erspan_idx_masked(struct match *match, uint32_t erspan_idx, + uint32_t mask) +{ + match->wc.masks.tunnel.erspan_idx = mask; + match->flow.tunnel.erspan_idx = erspan_idx & mask; +} + +void +match_set_tun_erspan_idx(struct match *match, uint32_t erspan_idx) +{ + match_set_tun_erspan_idx_masked(match, erspan_idx, UINT32_MAX); +} + +void +match_set_tun_erspan_dir_masked(struct match *match, uint8_t dir, + uint8_t mask) +{ + match->wc.masks.tunnel.erspan_dir = dir; + match->flow.tunnel.erspan_dir = dir & mask; +} + +void +match_set_tun_erspan_dir(struct match *match, uint8_t dir) +{ + match_set_tun_erspan_dir_masked(match, dir, UINT8_MAX); +} + +void +match_set_tun_erspan_hwid_masked(struct match *match, uint8_t hwid, + uint8_t mask) +{ + match->wc.masks.tunnel.erspan_hwid = hwid; + match->flow.tunnel.erspan_hwid = hwid & mask; +} + +void +match_set_tun_erspan_hwid(struct match *match, uint8_t hwid) +{ + match_set_tun_erspan_hwid_masked(match, hwid, UINT8_MAX); +} + +void match_set_in_port(struct match *match, ofp_port_t ofp_port) { match->wc.masks.in_port.ofp_port = u16_to_ofp(UINT16_MAX); @@ -1232,6 +1287,18 @@ format_flow_tunnel(struct ds *s, const struct match *match) if (wc->masks.tunnel.ip_ttl) { ds_put_format(s, "tun_ttl=%"PRIu8",", tnl->ip_ttl); } + if (wc->masks.tunnel.erspan_ver) { + ds_put_format(s, "erspan_ver=%"PRIu8",", tnl->erspan_ver); + } + if (wc->masks.tunnel.erspan_idx && tnl->erspan_ver == 1) { + ds_put_format(s, "erspan_idx=%#"PRIx32",", tnl->erspan_idx); + } + if (wc->masks.tunnel.erspan_dir && tnl->erspan_ver == 2) { + ds_put_format(s, "erspan_dir=%"PRIu8",", tnl->erspan_dir); + } + if (wc->masks.tunnel.erspan_hwid && tnl->erspan_ver == 2) { + ds_put_format(s, "erspan_hwid=%#"PRIx8",", tnl->erspan_hwid); + } if (wc->masks.tunnel.flags & FLOW_TNL_F_MASK) { format_flags_masked(s, "tun_flags", flow_tun_flag_to_string, tnl->flags & FLOW_TNL_F_MASK, @@ -1303,7 +1370,7 @@ match_format(const struct match *match, bool is_megaflow = false; int i; - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41); if (priority != OFP_DEFAULT_PRIORITY) { ds_put_format(s, "%spriority=%s%d,", diff --git a/lib/meta-flow.c b/lib/meta-flow.c index aa2ec012d671..8b8d174c163b 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -231,6 +231,14 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc) return !wc->masks.tunnel.gbp_id; case MFF_TUN_GBP_FLAGS: return !wc->masks.tunnel.gbp_flags; + case MFF_TUN_ERSPAN_VER: + return !wc->masks.tunnel.erspan_ver; + case MFF_TUN_ERSPAN_IDX: + return !wc->masks.tunnel.erspan_idx; + case MFF_TUN_ERSPAN_DIR: + return !wc->masks.tunnel.erspan_dir; + case MFF_TUN_ERSPAN_HWID: + return !wc->masks.tunnel.erspan_hwid; CASE_MFF_TUN_METADATA: return !ULLONG_GET(wc->masks.tunnel.metadata.present.map, mf->id - MFF_TUN_METADATA0); @@ -513,6 +521,10 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value) case MFF_TUN_TTL: case MFF_TUN_GBP_ID: case MFF_TUN_GBP_FLAGS: + case MFF_TUN_ERSPAN_IDX: + case MFF_TUN_ERSPAN_VER: + case MFF_TUN_ERSPAN_DIR: + case MFF_TUN_ERSPAN_HWID: CASE_MFF_TUN_METADATA: case MFF_METADATA: case MFF_IN_PORT: @@ -680,6 +692,18 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow, case MFF_TUN_TOS: value->u8 = flow->tunnel.ip_tos; break; + case MFF_TUN_ERSPAN_VER: + value->u8 = flow->tunnel.erspan_ver; + break; + case MFF_TUN_ERSPAN_IDX: + value->be32 = htonl(flow->tunnel.erspan_idx); + break; + case MFF_TUN_ERSPAN_DIR: + value->u8 = flow->tunnel.erspan_dir; + break; + case MFF_TUN_ERSPAN_HWID: + value->u8 = flow->tunnel.erspan_hwid; + break; CASE_MFF_TUN_METADATA: tun_metadata_read(&flow->tunnel, mf, value); break; @@ -994,6 +1018,18 @@ mf_set_value(const struct mf_field *mf, case MFF_TUN_TTL: match_set_tun_ttl(match, value->u8); break; + case MFF_TUN_ERSPAN_VER: + match_set_tun_erspan_ver(match, value->u8); + break; + case MFF_TUN_ERSPAN_IDX: + match_set_tun_erspan_idx(match, ntohl(value->be32)); + break; + case MFF_TUN_ERSPAN_DIR: + match_set_tun_erspan_dir(match, value->u8); + break; + case MFF_TUN_ERSPAN_HWID: + match_set_tun_erspan_hwid(match, value->u8); + break; CASE_MFF_TUN_METADATA: tun_metadata_set_match(mf, value, NULL, match, err_str); break; @@ -1391,6 +1427,18 @@ mf_set_flow_value(const struct mf_field *mf, case MFF_TUN_TTL: flow->tunnel.ip_ttl = value->u8; break; + case MFF_TUN_ERSPAN_VER: + flow->tunnel.erspan_ver = value->u8; + break; + case MFF_TUN_ERSPAN_IDX: + flow->tunnel.erspan_idx = ntohl(value->be32); + break; + case MFF_TUN_ERSPAN_DIR: + flow->tunnel.erspan_dir = value->u8; + break; + case MFF_TUN_ERSPAN_HWID: + flow->tunnel.erspan_hwid = value->u8; + break; CASE_MFF_TUN_METADATA: tun_metadata_write(&flow->tunnel, mf, value); break; @@ -1700,6 +1748,10 @@ mf_is_pipeline_field(const struct mf_field *mf) case MFF_TUN_FLAGS: case MFF_TUN_GBP_ID: case MFF_TUN_GBP_FLAGS: + case MFF_TUN_ERSPAN_VER: + case MFF_TUN_ERSPAN_IDX: + case MFF_TUN_ERSPAN_DIR: + case MFF_TUN_ERSPAN_HWID: CASE_MFF_TUN_METADATA: case MFF_METADATA: case MFF_IN_PORT: @@ -1876,6 +1928,18 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str) case MFF_TUN_TTL: match_set_tun_ttl_masked(match, 0, 0); break; + case MFF_TUN_ERSPAN_VER: + match_set_tun_erspan_ver_masked(match, 0, 0); + break; + case MFF_TUN_ERSPAN_IDX: + match_set_tun_erspan_idx_masked(match, 0, 0); + break; + case MFF_TUN_ERSPAN_DIR: + match_set_tun_erspan_dir_masked(match, 0, 0); + break; + case MFF_TUN_ERSPAN_HWID: + match_set_tun_erspan_hwid_masked(match, 0, 0); + break; CASE_MFF_TUN_METADATA: tun_metadata_set_match(mf, NULL, NULL, match, err_str); break; @@ -2256,6 +2320,19 @@ mf_set(const struct mf_field *mf, case MFF_TUN_TOS: match_set_tun_tos_masked(match, value->u8, mask->u8); break; + case MFF_TUN_ERSPAN_VER: + match_set_tun_erspan_ver_masked(match, value->u8, mask->u8); + break; + case MFF_TUN_ERSPAN_IDX: + match_set_tun_erspan_idx_masked(match, ntohl(value->be32), + ntohl(mask->be32)); + break; + case MFF_TUN_ERSPAN_DIR: + match_set_tun_erspan_dir_masked(match, value->u8, mask->u8); + break; + case MFF_TUN_ERSPAN_HWID: + match_set_tun_erspan_hwid_masked(match, value->u8, mask->u8); + break; CASE_MFF_TUN_METADATA: tun_metadata_set_match(mf, value, mask, match, err_str); break; diff --git a/lib/meta-flow.xml b/lib/meta-flow.xml index 933d4b86b090..8c7aa00ad769 100644 --- a/lib/meta-flow.xml +++ b/lib/meta-flow.xml @@ -1456,6 +1456,7 @@ ovs-ofctl add-flow br-int 'in_port=3,tun_src=192.168.1.1,tun_id=5001 actions=1'
  • LISP has a 24-bit instance ID.
  • GRE has an optional 32-bit key.
  • STT has a 64-bit key.
  • +
  • ERSPAN has a 10-bit key (Session ID).
  • @@ -1715,6 +1716,91 @@ ovs-ofctl add-flow br-int 'in_port=3,tun_src=192.168.1.1,tun_id=5001 actions=1' +

    ERSPAN Metadata Fields FIXME

    +

    + These fields provide access to features in the ERSPAN tunneling + protocol. The ERSPAN header is defined in the draft +

    + +

    + ERSPAN version number. 1 for version 1 (type II) + or 2 for version 2 (type III). +

    +
    + +

    ERSPAN version 1 header format:

    + +
    + + + +
    +
    + + + + + +
    +
    + + + +
    + +
    + +

    ERSPAN has a fixed 8-byte GRE header, including 4-byte GRE base header + another 4-byte sequence number. The ERSPAN's 10-bit session ID holds + the tunnel ID. +

    + +

    + ERSPAN index is a 20-bit index/port number associated with the ERSPAN + traffic's source port and direction (ingress/egress). This field is + platform dependent. +

    +
    + +

    ERSPAN version 2 header format:

    + +
    + + + +
    +
    + + + + + + + + +
    +
    + + + +
    + +
    + + +

    + Specifies the ERSPAN v2 mirrored traffic's direction. + Value 1 for egress traffic, and value 0 for ingress traffic. +

    +
    + +

    + ERSPAN hardware ID is a 6-bit unique identifier of an + ERSPAN v2 engine within a system. +

    +
    +

    Geneve Fields

    diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c index 288930a59529..183b112a24ac 100644 --- a/lib/netdev-native-tnl.c +++ b/lib/netdev-native-tnl.c @@ -517,6 +517,178 @@ netdev_gre_build_header(const struct netdev *netdev, } struct dp_packet * +netdev_erspan_pop_header(struct dp_packet *packet) +{ + const struct gre_base_hdr *greh; + const struct erspan_base_hdr *ersh; + struct pkt_metadata *md = &packet->md; + struct flow_tnl *tnl = &md->tunnel; + int hlen = sizeof(struct eth_header); + unsigned int ulen; + uint16_t greh_protocol; + + hlen += netdev_tnl_is_header_ipv6(dp_packet_data(packet)) ? + IPV6_HEADER_LEN : IP_HEADER_LEN; + + pkt_metadata_init_tnl(md); + if (hlen > dp_packet_size(packet)) { + goto err; + } + + greh = netdev_tnl_ip_extract_tnl_md(packet, tnl, &ulen); + if (!greh) { + goto err; + } + + greh_protocol = ntohs(greh->protocol); + if (greh_protocol != ETH_TYPE_ERSPAN1 && + greh_protocol != ETH_TYPE_ERSPAN2) { + goto err; + } + + if (greh->flags & ~htons(GRE_SEQ)) { + goto err; + } + + ersh = ERSPAN_HDR(greh); + tnl->tun_id = be32_to_be64(be16_to_be32(htons(get_sid(ersh)))); + tnl->erspan_ver = ersh->ver; + + if (ersh->ver == 1) { + ovs_be32 *index; + index = (ovs_be32 *)(ersh + 1); + tnl->erspan_idx = ntohl(*index); + tnl->flags |= FLOW_TNL_F_KEY; + hlen = ulen + ERSPAN_GREHDR_LEN + sizeof *ersh + ERSPAN_V1_MDSIZE; + } else if (ersh->ver == 2) { + struct erspan_md2 *md2; + + md2 = (struct erspan_md2 *)(ersh + 1); + tnl->erspan_dir = md2->dir; + tnl->erspan_hwid = get_hwid(md2); + tnl->flags |= FLOW_TNL_F_KEY; + hlen = ulen + ERSPAN_GREHDR_LEN + sizeof *ersh + ERSPAN_V2_MDSIZE; + } else { + VLOG_WARN_RL(&err_rl, "ERSPAN version error %d", ersh->ver); + goto err; + } + + if (hlen > dp_packet_size(packet)) { + goto err; + } + + dp_packet_reset_packet(packet, hlen); + + return packet; +err: + dp_packet_delete(packet); + return NULL; +} + +void +netdev_erspan_push_header(const struct netdev *netdev, + struct dp_packet *packet, + const struct ovs_action_push_tnl *data) +{ + struct netdev_vport *dev = netdev_vport_cast(netdev); + struct netdev_tunnel_config *tnl_cfg; + struct erspan_base_hdr *ersh; + struct gre_base_hdr *greh; + struct erspan_md2 *md2; + int ip_tot_size; + ovs_be32 *seqno; + + greh = netdev_tnl_push_ip_header(packet, data->header, + data->header_len, &ip_tot_size); + + /* update GRE seqno */ + tnl_cfg = &dev->tnl_cfg; + seqno = (ovs_be32 *)(greh + 1); + *seqno = htonl(tnl_cfg->seqno++); + + /* update v2 timestamp */ + if (greh->protocol == htons(ETH_TYPE_ERSPAN2)) { + ersh = ERSPAN_HDR(greh); + md2 = (struct erspan_md2 *)(ersh + 1); + md2->timestamp = get_erspan_ts(ERSPAN_100US); + } + return; +} + +int +netdev_erspan_build_header(const struct netdev *netdev, + struct ovs_action_push_tnl *data, + const struct netdev_tnl_build_header_params *params) +{ + struct netdev_vport *dev = netdev_vport_cast(netdev); + struct netdev_tunnel_config *tnl_cfg; + struct gre_base_hdr *greh; + struct erspan_base_hdr *ersh; + unsigned int hlen; + uint32_t tun_id; + uint16_t sid; + + /* XXX: RCUfy tnl_cfg. */ + ovs_mutex_lock(&dev->mutex); + tnl_cfg = &dev->tnl_cfg; + greh = netdev_tnl_ip_build_header(data, params, IPPROTO_GRE); + ersh = ERSPAN_HDR(greh); + + tun_id = ntohl(be64_to_be32(params->flow->tunnel.tun_id)); + /* ERSPAN only has 10-bit session ID */ + if (tun_id & ~ERSPAN_SID_MASK) { + return 1; + } else { + sid = (uint16_t) tun_id; + } + + if (tnl_cfg->erspan_ver == 1) { + ovs_be32 *index; + + greh->protocol = htons(ETH_TYPE_ERSPAN1); + greh->flags = htons(GRE_SEQ); + ersh->ver = 1; + set_sid(ersh, sid); + + index = (ovs_be32 *)(ersh + 1); + *index = htonl(tnl_cfg->erspan_idx); + + hlen = ERSPAN_GREHDR_LEN + sizeof *ersh + ERSPAN_V1_MDSIZE; + } else if (tnl_cfg->erspan_ver == 2) { + struct erspan_md2 *md2; + + greh->protocol = htons(ETH_TYPE_ERSPAN2); + greh->flags = htons(GRE_SEQ); + ersh->ver = 2; + set_sid(ersh, sid); + + md2 = (struct erspan_md2 *)(ersh + 1); + md2->sgt = 0; /* security group tag */ + md2->gra = 0; + md2->timestamp = 0; + set_hwid(md2, tnl_cfg->erspan_hwid); + md2->dir = tnl_cfg->erspan_dir; + + hlen = ERSPAN_GREHDR_LEN + sizeof *ersh + ERSPAN_V2_MDSIZE; + } else { + VLOG_WARN_RL(&err_rl, "ERSPAN version error %d", tnl_cfg->erspan_ver); + ovs_mutex_unlock(&dev->mutex); + return 1; + } + + ovs_mutex_unlock(&dev->mutex); + + data->header_len += hlen; + + if (params->is_ipv6) { + data->tnl_type = OVS_VPORT_TYPE_IP6ERSPAN; + } else { + data->tnl_type = OVS_VPORT_TYPE_ERSPAN; + } + return 0; +} + +struct dp_packet * netdev_vxlan_pop_header(struct dp_packet *packet) { struct pkt_metadata *md = &packet->md; diff --git a/lib/netdev-native-tnl.h b/lib/netdev-native-tnl.h index 5012b2dbac9a..5dc00122d93e 100644 --- a/lib/netdev-native-tnl.h +++ b/lib/netdev-native-tnl.h @@ -40,6 +40,18 @@ netdev_gre_push_header(const struct netdev *netdev, struct dp_packet * netdev_gre_pop_header(struct dp_packet *packet); +int +netdev_erspan_build_header(const struct netdev *netdev, + struct ovs_action_push_tnl *data, + const struct netdev_tnl_build_header_params *p); + +void +netdev_erspan_push_header(const struct netdev *netdev, + struct dp_packet *packet, + const struct ovs_action_push_tnl *data); +struct dp_packet * +netdev_erspan_pop_header(struct dp_packet *packet); + void netdev_tnl_push_udp_header(const struct netdev *netdev, struct dp_packet *packet, diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index cc50aa5efdd6..4311d2b8843c 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -544,6 +544,38 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp) } else if (!strcmp(node->key, "egress_pkt_mark")) { tnl_cfg.egress_pkt_mark = strtoul(node->value, NULL, 10); tnl_cfg.set_egress_pkt_mark = true; + } else if (!strcmp(node->key, "erspan_idx")) { + tnl_cfg.erspan_idx = strtol(node->value, NULL, 16); + if (tnl_cfg.erspan_idx & ~ERSPAN_IDX_MASK) { + ds_put_format(&errors, "%s: invalid erspan index: %s\n", + name, node->value); + err = EINVAL; + goto out; + } + } else if (!strcmp(node->key, "erspan_ver")) { + tnl_cfg.erspan_ver = atoi(node->value); + if (tnl_cfg.erspan_ver != 1 && tnl_cfg.erspan_ver != 2) { + ds_put_format(&errors, "%s: invalid erspan version: %s\n", + name, node->value); + err = EINVAL; + goto out; + } + } else if (!strcmp(node->key, "erspan_dir")) { + tnl_cfg.erspan_dir = atoi(node->value); + if (tnl_cfg.erspan_dir != 0 && tnl_cfg.erspan_dir != 1) { + ds_put_format(&errors, "%s: invalid erspan direction: %s\n", + name, node->value); + err = EINVAL; + goto out; + } + } else if (!strcmp(node->key, "erspan_hwid")) { + tnl_cfg.erspan_hwid = strtol(node->value, NULL, 16); + if (tnl_cfg.erspan_hwid & ~(ERSPAN_HWID_MASK >> 4)) { + ds_put_format(&errors, "%s: invalid erspan hardware ID: %s\n", + name, node->value); + err = EINVAL; + goto out; + } } else { ds_put_format(&errors, "%s: unknown %s argument '%s'\n", name, type, node->key); @@ -734,6 +766,20 @@ get_tunnel_config(const struct netdev *dev, struct smap *args) smap_add_format(args, "egress_pkt_mark", "%"PRIu32, tnl_cfg.egress_pkt_mark); } + + if (tnl_cfg.erspan_idx) { + smap_add_format(args, "erspan_idx", "0x%x", tnl_cfg.erspan_idx); + } + if (tnl_cfg.erspan_ver) { + smap_add_format(args, "erspan_ver", "%d", tnl_cfg.erspan_ver); + } + if (tnl_cfg.erspan_dir) { + smap_add_format(args, "erspan_dir", "%d", tnl_cfg.erspan_dir); + } + if (tnl_cfg.erspan_hwid) { + smap_add_format(args, "erspan_hwid", "0x%x", tnl_cfg.erspan_hwid); + } + return 0; } @@ -988,6 +1034,14 @@ netdev_vport_tunnel_register(void) NETDEV_VPORT_GET_IFINDEX), TUNNEL_CLASS("lisp", "lisp_sys", NULL, NULL, NULL, NULL), TUNNEL_CLASS("stt", "stt_sys", NULL, NULL, NULL, NULL), + TUNNEL_CLASS("erspan", "erspan_sys", netdev_erspan_build_header, + netdev_erspan_push_header, + netdev_erspan_pop_header, + NULL), + TUNNEL_CLASS("ip6erspan", "ip6erspan_sys", netdev_erspan_build_header, + netdev_erspan_push_header, + netdev_erspan_pop_header, + NULL), }; static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; diff --git a/lib/netdev.h b/lib/netdev.h index 2258c0718986..f03cbbcf61c4 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -130,6 +130,10 @@ struct netdev_tunnel_config { bool set_seq; uint32_t seqno; + uint32_t erspan_idx; + uint8_t erspan_ver; + uint8_t erspan_dir; + uint8_t erspan_hwid; }; void netdev_run(void); diff --git a/lib/nx-match.c b/lib/nx-match.c index a8edb2e9d245..dca2999f9401 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -1026,7 +1026,7 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match, ovs_be32 spi_mask; int match_len; - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41); struct nxm_put_ctx ctx = { .output = b, .implied_ethernet = false }; @@ -1155,6 +1155,17 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match, flow->tunnel.gbp_flags, match->wc.masks.tunnel.gbp_flags); tun_metadata_to_nx_match(b, oxm, match); + /* ERSPAN */ + nxm_put_32m(&ctx, MFF_TUN_ERSPAN_IDX, oxm, + htonl(flow->tunnel.erspan_idx), + htonl(match->wc.masks.tunnel.erspan_idx)); + nxm_put_8m(&ctx, MFF_TUN_ERSPAN_VER, oxm, + flow->tunnel.erspan_ver, match->wc.masks.tunnel.erspan_ver); + nxm_put_8m(&ctx, MFF_TUN_ERSPAN_DIR, oxm, + flow->tunnel.erspan_dir, match->wc.masks.tunnel.erspan_dir); + nxm_put_8m(&ctx, MFF_TUN_ERSPAN_HWID, oxm, + flow->tunnel.erspan_hwid, match->wc.masks.tunnel.erspan_hwid); + /* Network Service Header */ nxm_put_8m(&ctx, MFF_NSH_FLAGS, oxm, flow->nsh.flags, match->wc.masks.nsh.flags); diff --git a/lib/odp-util.c b/lib/odp-util.c index 5da83b4c64c4..c39bc7d5b814 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -712,6 +712,30 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data) options++; } ds_put_format(ds, ")"); + } else if (data->tnl_type == OVS_VPORT_TYPE_ERSPAN || + data->tnl_type == OVS_VPORT_TYPE_IP6ERSPAN) { + const struct gre_base_hdr *greh; + const struct erspan_base_hdr *ersh; + + greh = (const struct gre_base_hdr *) l4; + ersh = ERSPAN_HDR(greh); + + if (ersh->ver == 1) { + const ovs_be32 *index; + + index = (const ovs_be32 *)(ersh + 1); + ds_put_format(ds, "erspan(ver=1,sid=0x%"PRIx16",idx=0x%"PRIx32")", + get_sid(ersh), ntohl(*index)); + } else if (ersh->ver == 2) { + const struct erspan_md2 *md2; + + md2 = (const struct erspan_md2 *)(ersh + 1); + ds_put_format(ds, "erspan(ver=2,sid=0x%"PRIx16 + ",dir=%"PRIu8",hwid=0x%"PRIx8")", + get_sid(ersh), md2->dir, get_hwid(md2)); + } else { + VLOG_WARN("%s Invalid ERSPAN version %d\n", __func__, ersh->ver); + } } ds_put_format(ds, ")"); } @@ -1399,11 +1423,14 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data) struct ovs_16aligned_ip6_hdr *ip6; struct udp_header *udp; struct gre_base_hdr *greh; - uint16_t gre_proto, gre_flags, dl_type, udp_src, udp_dst, csum; + struct erspan_base_hdr *ersh; + struct erspan_md2 *md2; + uint16_t gre_proto, gre_flags, dl_type, udp_src, udp_dst, csum, sid; ovs_be32 sip, dip; - uint32_t tnl_type = 0, header_len = 0, ip_len = 0; + uint32_t tnl_type = 0, header_len = 0, ip_len = 0, erspan_idx = 0; void *l3, *l4; int n = 0; + uint8_t hwid, dir; if (!ovs_scan_len(s, &n, "tnl_push(tnl_port(%"SCNi32"),", &data->tnl_port)) { return -EINVAL; @@ -1574,6 +1601,58 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data) header_len = sizeof *eth + ip_len + ((uint8_t *) options - (uint8_t *) greh); + } else if (ovs_scan_len(s, &n, "erspan(ver=1,sid="SCNx16",idx=0x"SCNx32")", + &sid, &erspan_idx)) { + ovs_be32 *index; + + ersh = ERSPAN_HDR(greh); + index = (ovs_be32 *)(ersh + 1); + + if (eth->eth_type == htons(ETH_TYPE_IP)) { + tnl_type = OVS_VPORT_TYPE_ERSPAN; + } else { + tnl_type = OVS_VPORT_TYPE_IP6ERSPAN; + } + + greh->flags = htons(GRE_SEQ); + greh->protocol = htons(ETH_TYPE_ERSPAN1); + + ersh->ver = 1; + set_sid(ersh, sid); + *index = htonl(erspan_idx); + + if (!ovs_scan_len(s, &n, ")")) { + return -EINVAL; + } + header_len = sizeof *eth + ip_len + ERSPAN_GREHDR_LEN + + sizeof *ersh + ERSPAN_V1_MDSIZE; + + } else if (ovs_scan_len(s, &n, "erspan(ver=2,sid="SCNx16"dir="SCNu8 + ",hwid=0x"SCNx8")", &sid, &dir, &hwid)) { + + ersh = ERSPAN_HDR(greh); + md2 = (struct erspan_md2 *)(ersh + 1); + + if (eth->eth_type == htons(ETH_TYPE_IP)) { + tnl_type = OVS_VPORT_TYPE_ERSPAN; + } else { + tnl_type = OVS_VPORT_TYPE_IP6ERSPAN; + } + + greh->flags = htons(GRE_SEQ); + greh->protocol = htons(ETH_TYPE_ERSPAN2); + + ersh->ver = 2; + set_sid(ersh, sid); + set_hwid(md2, hwid); + md2->dir = dir; + + if (!ovs_scan_len(s, &n, ")")) { + return -EINVAL; + } + + header_len = sizeof *eth + ip_len + ERSPAN_GREHDR_LEN + + sizeof *ersh + ERSPAN_V2_MDSIZE; } else { return -EINVAL; } diff --git a/lib/odp-util.h b/lib/odp-util.h index 1fad159db9fb..6d5538f7f022 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -147,7 +147,7 @@ void odp_portno_name_format(const struct hmap *portno_names, * add another field and forget to adjust this value. */ #define ODPUTIL_FLOW_KEY_BYTES 640 -BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40); +BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41); /* A buffer with sufficient size and alignment to hold an nlattr-formatted flow * key. An array of "struct nlattr" might not, in theory, be sufficiently diff --git a/lib/ofp-match.c b/lib/ofp-match.c index d1031f6aaa3e..58591521a4db 100644 --- a/lib/ofp-match.c +++ b/lib/ofp-match.c @@ -65,7 +65,7 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask) void ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc) { - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41); /* Initialize most of wc. */ flow_wildcards_init_catchall(wc); diff --git a/lib/packets.h b/lib/packets.h index 9a71aa3abbdb..acd7a4746482 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -32,6 +32,7 @@ #include "tun-metadata.h" #include "unaligned.h" #include "util.h" +#include "timeval.h" struct dp_packet; struct ds; @@ -404,6 +405,8 @@ ovs_be32 set_mpls_lse_values(uint8_t ttl, uint8_t tc, uint8_t bos, #define ETH_TYPE_MPLS 0x8847 #define ETH_TYPE_MPLS_MCAST 0x8848 #define ETH_TYPE_NSH 0x894f +#define ETH_TYPE_ERSPAN1 0x88be /* version 1 type II */ +#define ETH_TYPE_ERSPAN2 0x22eb /* version 2 type III */ static inline bool eth_type_mpls(ovs_be16 eth_type) { @@ -1246,6 +1249,129 @@ struct gre_base_hdr { #define GRE_FLAGS 0x00F8 #define GRE_VERSION 0x0007 +/* + * ERSPAN protocol header and metadata + * + * Version 1 (Type II) header (8 octets [42:49]) + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Ver | VLAN | COS | En|T| Session ID | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reserved | Index | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * + * ERSPAN Version 2 (Type III) header (12 octets [42:49]) + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Ver | VLAN | COS |BSO|T| Session ID | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Timestamp | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | SGT |P| FT | Hw ID |D|Gra|O| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ + +/* ERSPAN has fixed 8-byte GRE header */ +#define ERSPAN_GREHDR_LEN 8 +#define ERSPAN_HDR(gre_base_hdr) \ + ((struct erspan_base_hdr *)((char *)gre_base_hdr + ERSPAN_GREHDR_LEN)) + +#define ERSPAN_V1_MDSIZE 4 +#define ERSPAN_V2_MDSIZE 8 + +#define ERSPAN_SID_MASK 0x03ff /* 10-bit Session ID. */ +#define ERSPAN_IDX_MASK 0xfffff /* v1 Index */ +#define ERSPAN_HWID_MASK 0x03f0 +#define ERSPAN_DIR_MASK 0x0008 + +struct erspan_base_hdr { + uint8_t vlan_upper:4, + ver:4; + uint8_t vlan:8; + uint8_t session_id_upper:2, + t:1, + en:2, + cos:3; + uint8_t session_id:8; +}; + +struct erspan_md2 { + ovs_be32 timestamp; + ovs_be16 sgt; + uint8_t hwid_upper:2, + ft:5, + p:1; + uint8_t o:1, + gra:2, + dir:1, + hwid:4; +}; + +struct erspan_metadata { + int version; + union { + ovs_be32 index; /* Version 1 (type II)*/ + struct erspan_md2 md2; /* Version 2 (type III) */ + } u; +}; + +static inline uint16_t get_sid(const struct erspan_base_hdr *ershdr) +{ + return (ershdr->session_id_upper << 8) + ershdr->session_id; +} + +static inline void set_sid(struct erspan_base_hdr *ershdr, uint16_t id) +{ + ershdr->session_id = id & 0xff; + ershdr->session_id_upper = (id >> 8) &0x3; +} + +static inline uint8_t get_hwid(const struct erspan_md2 *md2) +{ + return (md2->hwid_upper << 4) + md2->hwid; +} + +static inline void set_hwid(struct erspan_md2 *md2, uint8_t hwid) +{ + md2->hwid = hwid & 0xf; + md2->hwid_upper = (hwid >> 4) & 0x3; +} + +/* ERSPAN timestamp granularity + * 00b --> granularity = 100 microseconds + * 01b --> granularity = 100 nanoseconds + * 10b --> granularity = IEEE 1588 + * Here we only support 100 microseconds. + */ +enum erspan_ts_gra { + ERSPAN_100US, + ERSPAN_100NS, + ERSPAN_IEEE1588, +}; + +static inline ovs_be32 get_erspan_ts(enum erspan_ts_gra gra) +{ + ovs_be32 ts = 0; + + switch (gra) { + case ERSPAN_100US: + ts = htonl((uint32_t)(time_wall_usec() / 100)); + break; + case ERSPAN_100NS: + /* fall back */ + case ERSPAN_IEEE1588: + /* fall back */ + default: + OVS_NOT_REACHED(); + break; + } + return ts; +} + /* VXLAN protocol header */ struct vxlanhdr { union { diff --git a/lib/tnl-ports.c b/lib/tnl-ports.c index b814f7a0a50a..57531794c969 100644 --- a/lib/tnl-ports.c +++ b/lib/tnl-ports.c @@ -171,7 +171,8 @@ tnl_type_to_nw_proto(const char type[]) if (!strcmp(type, "stt")) { return IPPROTO_TCP; } - if (!strcmp(type, "gre")) { + if (!strcmp(type, "gre") || !strcmp(type, "erspan") || + !strcmp(type, "ip6erspan")) { return IPPROTO_GRE; } if (!strcmp(type, "vxlan")) { diff --git a/ofproto/ofproto-dpif-rid.h b/ofproto/ofproto-dpif-rid.h index 441584af80f3..ab5b87a0521a 100644 --- a/ofproto/ofproto-dpif-rid.h +++ b/ofproto/ofproto-dpif-rid.h @@ -99,7 +99,7 @@ struct rule; /* Metadata for restoring pipeline context after recirculation. Helpers * are inlined below to keep them together with the definition for easier * updates. */ -BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40); +BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41); struct frozen_metadata { /* Metadata in struct flow. */ diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index bc6429c25346..50b1ca507083 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -3266,6 +3266,8 @@ propagate_tunnel_data_to_flow(struct xlate_ctx *ctx, struct eth_addr dmac, switch (tnl_type) { case OVS_VPORT_TYPE_GRE: + case OVS_VPORT_TYPE_ERSPAN: + case OVS_VPORT_TYPE_IP6ERSPAN: nw_proto = IPPROTO_GRE; break; case OVS_VPORT_TYPE_VXLAN: @@ -3741,7 +3743,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, /* If 'struct flow' gets additional metadata, we'll need to zero it out * before traversing a patch port. */ - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41); memset(&flow_tnl, 0, sizeof flow_tnl); if (!check_output_prerequisites(ctx, xport, flow, check_stp)) { diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c index e0214ced69e2..2df4f0ce6911 100644 --- a/ofproto/tunnel.c +++ b/ofproto/tunnel.c @@ -474,6 +474,19 @@ tnl_port_send(const struct ofport_dpif *ofport, struct flow *flow, wc->masks.pkt_mark = UINT32_MAX; } + if (cfg->erspan_ver) { + flow->tunnel.erspan_ver = cfg->erspan_ver; + } + if (cfg->erspan_idx) { + flow->tunnel.erspan_idx = cfg->erspan_idx; + } + if (cfg->erspan_dir) { + flow->tunnel.erspan_dir = cfg->erspan_dir; + } + if (cfg->erspan_hwid) { + flow->tunnel.erspan_hwid = cfg->erspan_hwid; + } + if (pre_flow_str) { char *post_flow_str = flow_to_string(flow, NULL); char *tnl_str = tnl_port_to_string(tnl_port); diff --git a/tests/ofproto.at b/tests/ofproto.at index c1beea7aec89..ecf77b8105d0 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -2394,7 +2394,7 @@ head_table () { instructions: meter,apply_actions,clear_actions,write_actions,write_metadata,goto_table Write-Actions and Apply-Actions features: actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue - supported on Set-Field: tun_id tun_src tun_dst tun_ipv6_src tun_ipv6_dst tun_flags tun_gbp_id tun_gbp_flags tun_metadata0 dnl + supported on Set-Field: tun_id tun_src tun_dst tun_ipv6_src tun_ipv6_dst tun_flags tun_gbp_id tun_gbp_flags tun_erspan_idx tun_erspan_ver tun_erspan_dir tun_erspan_hwid tun_metadata0 dnl tun_metadata1 tun_metadata2 tun_metadata3 tun_metadata4 tun_metadata5 tun_metadata6 tun_metadata7 tun_metadata8 tun_metadata9 tun_metadata10 tun_metadata11 tun_metadata12 tun_metadata13 tun_metadata14 tun_metadata15 tun_metadata16 tun_metadata17 tun_metadata18 tun_metadata19 tun_metadata20 tun_metadata21 tun_metadata22 tun_metadata23 tun_metadata24 tun_metadata25 tun_metadata26 tun_metadata27 tun_metadata28 tun_metadata29 tun_metadata30 tun_metadata31 tun_metadata32 tun_metadata33 tun_metadata34 tun_metadata35 tun_metadata36 tun_metadata37 tun_metadata38 tun_metadata39 tun_metadata40 tun_metadata41 tun_metadata42 tun_metadata43 tun_metadata44 tun_metadata45 tun_metadata46 tun_metadata47 tun_metadata48 tun_metadata49 tun_metadata50 tun_metadata51 tun_metadata52 tun_metadata53 tun_metadata54 tun_metadata55 tun_metadata56 tun_metadata57 tun_metadata58 tun_metadata59 tun_metadata60 tun_metadata61 tun_metadata62 tun_metadata63 dnl metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 reg10 reg11 reg12 reg13 reg14 reg15 xreg0 xreg1 xreg2 xreg3 xreg4 xreg5 xreg6 xreg7 xxreg0 xxreg1 xxreg2 xxreg3 eth_src eth_dst vlan_tci vlan_vid vlan_pcp mpls_label mpls_tc mpls_ttl ip_src ip_dst ipv6_src ipv6_dst ipv6_label nw_tos ip_dscp nw_ecn nw_ttl arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst icmp_type icmp_code icmpv6_type icmpv6_code nd_target nd_sll nd_tll nsh_flags nsh_spi nsh_si nsh_c1 nsh_c2 nsh_c3 nsh_c4 nsh_ttl matching: @@ -2410,6 +2410,10 @@ metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 tun_flags: arbitrary mask tun_gbp_id: arbitrary mask tun_gbp_flags: arbitrary mask + tun_erspan_idx: arbitrary mask + tun_erspan_ver: arbitrary mask + tun_erspan_dir: arbitrary mask + tun_erspan_hwid: arbitrary mask tun_metadata0: arbitrary mask tun_metadata1: arbitrary mask tun_metadata2: arbitrary mask diff --git a/tests/tunnel-push-pop-ipv6.at b/tests/tunnel-push-pop-ipv6.at index 7ca522ae2a0f..6364a7c038da 100644 --- a/tests/tunnel-push-pop-ipv6.at +++ b/tests/tunnel-push-pop-ipv6.at @@ -1,5 +1,115 @@ AT_BANNER([tunnel_push_pop_ipv6]) +AT_SETUP([tunnel_push_pop_ipv6 - ip6erspan]) + +OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 other-config:hwaddr=aa:55:aa:55:00:00]) +AT_CHECK([ovs-vsctl add-br int-br -- set bridge int-br datapath_type=dummy], [0]) +AT_CHECK([ovs-vsctl add-port int-br t2 -- set Interface t2 type=ip6erspan \ + options:remote_ip=2001:cafe::92 options:key=123 \ + options:erspan_ver=1 options:erspan_idx=3 ofport_request=2\ + -- add-port int-br t3 -- set Interface t3 type=ip6erspan \ + options:remote_ip=2001:cafe::93 options:key=567 \ + options:erspan_ver=2 options:erspan_dir=1 options:erspan_hwid=0x7 \ + ofport_request=3\ + ], [0]) + +AT_CHECK([ovs-appctl dpif/show], [0], [dnl +dummy@ovs-dummy: hit:0 missed:0 + br0: + br0 65534/100: (dummy-internal) + p0 1/1: (dummy) + int-br: + int-br 65534/2: (dummy-internal) + t2 2/6: (ip6erspan: erspan_idx=0x3, erspan_ver=1, key=123, remote_ip=2001:cafe::92) + t3 3/6: (ip6erspan: erspan_dir=1, erspan_hwid=0x7, erspan_ver=2, key=567, remote_ip=2001:cafe::93) +]) + +dnl First setup dummy interface IP address, then add the route +dnl so that tnl-port table can get valid IP address for the device. +AT_CHECK([ovs-appctl netdev-dummy/ip6addr br0 2001:cafe::88/24], [0], [OK +]) +AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.2.88/24], [0], [OK +]) +AT_CHECK([ovs-appctl ovs/route/add 2001:cafe::92/24 br0], [0], [OK +]) + +AT_CHECK([ovs-ofctl add-flow br0 action=normal]) + +dnl Check Neighbour discovery. +AT_CHECK([ovs-vsctl -- set Interface p0 options:pcap=p0.pcap]) + +AT_CHECK([ovs-appctl netdev-dummy/receive int-br 'in_port(2),eth(src=aa:55:aa:55:00:00,dst=f8:bc:12:ff:ff:ff),eth_type(0x0800),ipv4(src=1.1.3.92,dst=1.1.3.88,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)']) +AT_CHECK([ovs-pcap p0.pcap > p0.pcap.txt 2>&1]) + +AT_CHECK([cat p0.pcap.txt | grep 92aa55aa55000086dd6000000000203aff2001cafe | uniq], [0], [dnl +3333ff000092aa55aa55000086dd6000000000203aff2001cafe000000000000000000000088ff0200000000000000000001ff00009287004d48000000002001cafe0000000000000000000000920101aa55aa550000 +]) +AT_CHECK([cat p0.pcap.txt | grep 93aa55aa55000086dd6000000000203aff2001cafe | uniq], [0], [dnl +3333ff000093aa55aa55000086dd6000000000203aff2001cafe000000000000000000000088ff0200000000000000000001ff00009387004d46000000002001cafe0000000000000000000000930101aa55aa550000 +]) + +dnl Check ARP Snoop +AT_CHECK([ovs-appctl netdev-dummy/receive br0 'in_port(100),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x86dd),ipv6(src=2001:cafe::92,dst=2001:cafe::94,label=0,proto=58,tclass=0,hlimit=255,frag=no),icmpv6(type=136,code=0),nd(target=2001:cafe::92,sll=00:00:00:00:00:00,tll=f8:bc:12:44:34:b6)']) + +AT_CHECK([ovs-appctl netdev-dummy/receive br0 'in_port(100),eth(src=f8:bc:12:44:34:b7,dst=aa:55:aa:55:00:00),eth_type(0x86dd),ipv6(src=2001:cafe::93,dst=2001:cafe::94,label=0,proto=58,tclass=0,hlimit=255,frag=no),icmpv6(type=136,code=0),nd(target=2001:cafe::93,sll=00:00:00:00:00:00,tll=f8:bc:12:44:34:b7)']) + +AT_CHECK([ovs-appctl tnl/arp/show | tail -n+3 | sort], [0], [dnl +2001:cafe::92 f8:bc:12:44:34:b6 br0 +2001:cafe::93 f8:bc:12:44:34:b7 br0 +]) + +AT_CHECK([ovs-appctl tnl/ports/show |sort], [0], [dnl +Listening ports: +ip6erspan_sys (6) ref_cnt=2 +]) + +dnl Check ERSPAN tunnel pop +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x86dd),ipv6(src=2001:cafe::92,dst=2001:cafe::88,label=0,proto=47,tclass=0x0,hlimit=64)'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: tnl_pop(6) +]) + +dnl Check ERSPAN v1 tunnel push +AT_CHECK([ovs-ofctl add-flow int-br action=2]) +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: tnl_push(tnl_port(6),header(size=70,type=108,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=47,tclass=0x0,hlimit=64),erspan(ver=1,sid=0x7b,idx=0x3)),out_port(100)) +]) + +dnl Check ERSPAN v2 tunnel push +AT_CHECK([ovs-ofctl mod-flows int-br action=3]) +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: tnl_push(tnl_port(6),header(size=74,type=108,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::93,label=0,proto=47,tclass=0x0,hlimit=64),erspan(ver=2,sid=0x237,dir=1,hwid=0x7)),out_port(100)) +]) + +ovs-appctl vlog/set dbg +dnl Check decapsulation of ERSPAN v1 +dnl Hex dump: GRE:(100088be) +dnl ERSPAN: v1, session id = 0x7b (1000007b), index=3 (00000003) +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6486dd60000000006a2f402001cafe0000000000000000000000922001cafe000000000000000000000088100088be000000011000007b00000003fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6486dd60000000006a2f402001cafe0000000000000000000000922001cafe000000000000000000000088100088be000000011000007b00000003fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) + +ovs-appctl time/warp 1000 + +AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port 2'], [0], [dnl + port 2: rx pkts=2, bytes=196, drop=?, errs=?, frame=?, over=?, crc=? +]) + +dnl Check decapsulation ERSPAN v2 +dnl Hex dump: GRE:(100022eb) +dnl ERSPAN: v2, session id = 0x237 (20000237), hwid = 8,dir = 1 (00000078) +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6486dd60000000006a2f402001cafe0000000000000000000000932001cafe000000000000000000000088100022eb000000012000023710abcd0100000078fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) + +ovs-appctl time/warp 1000 + +AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port 3'], [0], [dnl + port 3: rx pkts=1, bytes=98, drop=?, errs=?, frame=?, over=?, crc=? +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([tunnel_push_pop_ipv6 - action]) OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 other-config:hwaddr=aa:55:aa:55:00:00]) @@ -30,6 +140,14 @@ dummy@ovs-dummy: hit:0 missed:0 t5 6/3: (gre: key=455, packet_type=legacy_l3, remote_ip=2001:cafe::92) ]) +AT_CHECK([ovs-appctl tnl/ports/show |sort], [0], [dnl +Listening ports: +genev_sys_6081 (6081) ref_cnt=1 +gre_sys (3) ref_cnt=2 +vxlan_sys_4789 (4789) ref_cnt=2 +]) + + dnl First setup dummy interface IP address, then add the route dnl so that tnl-port table can get valid IP address for the device. AT_CHECK([ovs-appctl netdev-dummy/ip6addr br0 2001:cafe::88/24], [0], [OK diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at index dcea2b4c5826..9082692f3857 100644 --- a/tests/tunnel-push-pop.at +++ b/tests/tunnel-push-pop.at @@ -1,5 +1,142 @@ AT_BANNER([tunnel_push_pop]) +AT_SETUP([tunnel_push_pop - erspan]) +OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 other-config:hwaddr=aa:55:aa:55:00:00]) +AT_CHECK([ovs-vsctl add-br int-br -- set bridge int-br datapath_type=dummy], [0]) +AT_CHECK([ovs-vsctl add-port int-br t1 -- set Interface t1 type=erspan \ + options:remote_ip=1.1.2.92 options:key=123 options:erspan_ver=1 \ + options:erspan_idx=3 ofport_request=2 \ + -- add-port int-br t2 -- set Interface t2 type=erspan \ + options:remote_ip=1.1.2.92 options:key=567 options:erspan_ver=2 \ + options:erspan_dir=1 options:erspan_hwid=0x7 ofport_request=3\ + ], [0]) + +AT_CHECK([ovs-appctl dpif/show], [0], [dnl +dummy@ovs-dummy: hit:0 missed:0 + br0: + br0 65534/100: (dummy-internal) + p0 1/1: (dummy) + int-br: + int-br 65534/2: (dummy-internal) + t1 2/3: (erspan: erspan_idx=0x3, erspan_ver=1, key=123, remote_ip=1.1.2.92) + t2 3/3: (erspan: erspan_dir=1, erspan_hwid=0x7, erspan_ver=2, key=567, remote_ip=1.1.2.92) +]) + +dnl First setup dummy interface IP address, then add the route +dnl so that tnl-port table can get valid IP address for the device. +AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.2.88/24], [0], [OK +]) +AT_CHECK([ovs-appctl netdev-dummy/ip6addr br0 2001:cafe::88/24], [0], [OK +]) + +AT_CHECK([ovs-appctl ovs/route/add 1.1.2.92/24 br0], [0], [OK +]) + +AT_CHECK([ovs-appctl ovs/route/add 1.1.2.92/24 br0 pkt_mark=1234], [0], [OK +]) + +AT_CHECK([ovs-ofctl add-flow br0 action=normal]) + +dnl Check ARP request +AT_CHECK([ovs-vsctl -- set Interface p0 options:pcap=p0.pcap]) + +AT_CHECK([ovs-appctl netdev-dummy/receive int-br 'in_port(2),eth(src=aa:55:aa:55:00:00,dst=f8:bc:12:ff:ff:ff),eth_type(0x0800),ipv4(src=1.1.3.92,dst=1.1.3.88,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)']) + +dnl Wait for the two ARP requests to be sent. Sometimes the system +dnl can be slow (e.g. under valgrind) +OVS_WAIT_UNTIL([test `ovs-pcap p0.pcap | sort | uniq | wc -l` -ge 1]) + +AT_CHECK([ovs-pcap p0.pcap > p0.pcap.txt 2>&1]) + +AT_CHECK([cat p0.pcap.txt | grep 101025 | uniq], [0], [dnl +ffffffffffffaa55aa55000008060001080006040001aa55aa550000010102580000000000000101025c +]) + + +dnl Check ARP Snoop +AT_CHECK([ovs-appctl netdev-dummy/receive br0 'recirc_id(0),in_port(100),eth(src=f8:bc:12:44:34:b6,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=1.1.2.92,tip=1.1.2.88,op=2,sha=f8:bc:12:44:34:b6,tha=00:00:00:00:00:00)']) +AT_CHECK([ovs-appctl netdev-dummy/receive br0 'recirc_id(0),in_port(100),eth(src=f8:bc:12:44:34:b7,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=1.1.2.93,tip=1.1.2.88,op=2,sha=f8:bc:12:44:34:b7,tha=00:00:00:00:00:00)']) +AT_CHECK([ovs-appctl netdev-dummy/receive br0 'recirc_id(0),in_port(100),eth(src=f8:bc:12:44:34:b8,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=1.1.2.94,tip=1.1.2.88,op=2,sha=f8:bc:12:44:34:b8,tha=00:00:00:00:00:00)']) + +AT_CHECK([ovs-appctl tnl/neigh/show | tail -n+3 | sort], [0], [dnl +1.1.2.92 f8:bc:12:44:34:b6 br0 +1.1.2.93 f8:bc:12:44:34:b7 br0 +1.1.2.94 f8:bc:12:44:34:b8 br0 +]) + +AT_CHECK([ovs-appctl tnl/ports/show |sort], [0], [dnl +Listening ports: +erspan_sys (3) ref_cnt=2 +]) + +dnl Check ERSPAN v1 tunnel push +AT_CHECK([ovs-vsctl -- set Interface br0 options:pcap=br0.pcap]) +AT_CHECK([ovs-ofctl add-flow int-br action=2]) +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: tnl_push(tnl_port(3),header(size=50,type=107,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=1,sid=0x7b,idx=0x3)),out_port(100)) +]) + +dnl Check ERSPAN v2 tunnel push +AT_CHECK([ovs-ofctl mod-flows int-br action=3]) +AT_CHECK([ovs-appctl revalidator/wait]) +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: tnl_push(tnl_port(3),header(size=54,type=107,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x237,dir=1,hwid=0x7)),out_port(100)) +]) + +dnl Check ERSPAN tunnel pop +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.11.93,dst=1.1.2.88,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: tnl_pop(3) +]) + +AT_CHECK([ovs-ofctl del-flows int-br]) + +dnl Check decapsulation of ERSPAN v1 +dnl Hex dump: GRE:(100088be) +dnl ERSPAN: v1, session id = 0x7b (1000007b), index=3 (00000003) +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500007e79464000402fba550101025c01010258100088be000000011000007b00000003fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) + +AT_CHECK([ovs-appctl revalidator/wait]) +AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port 2'], [0], [dnl + port 2: rx pkts=1, bytes=98, drop=?, errs=?, frame=?, over=?, crc=? +]) + +dnl Check decapsulation ERSPAN v2 +dnl Hex dump: GRE:(100022eb) +dnl ERSPAN: v2, session id = 0x237 (20000237), hwid =7, dir = 1 (00000078) +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500007e79464000402fba550101025c01010258100022eb000000012000023710abcd0100000078fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) + +AT_CHECK([ovs-appctl revalidator/wait]) +AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port 3'], [0], [dnl + port 3: rx pkts=1, bytes=98, drop=?, errs=?, frame=?, over=?, crc=? +]) + +dnl Check ERSPAN encap in pcap file +dnl This ARP reply from p0 has two effects: +dnl 1. The ARP cache will learn that 1.1.2.92 is at f8:bc:12:44:34:b6. +dnl 2. The br0 mac learning will learn that f8:bc:12:44:34:b6 is on p0. +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'recirc_id(0),in_port(2),eth(src=f8:bc:12:44:34:b6,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=1.1.2.92,tip=1.1.2.88,op=2,sha=f8:bc:12:44:34:b6,tha=00:00:00:00:00:00)']) + +AT_CHECK([ovs-vsctl -- set Interface p0 options:tx_pcap=p0.pcap]) + +dnl Output to tunnel from a int-br internal port +AT_CHECK([ovs-ofctl add-flow int-br "in_port=LOCAL,actions=output:2"]) +AT_CHECK([ovs-appctl revalidator/wait]) +AT_CHECK([ovs-appctl netdev-dummy/receive int-br '50540000000a5054000000091234']) +dnl 100088be: GRE with ERSPANv1, 00000001: Seqno, 1000007b: v1 with 0x7b session ID (key) +OVS_WAIT_UNTIL([test `ovs-pcap p0.pcap | grep 100088be000000011000007b | wc -l` -ge 1]) + +AT_CHECK([ovs-ofctl mod-flows int-br "in_port=LOCAL,actions=output:3"]) +AT_CHECK([ovs-appctl revalidator/wait]) +AT_CHECK([ovs-appctl netdev-dummy/receive int-br '50540000000a5054000000091235']) +dnl 100022eb: GRE with ERSPANv2, 00000001: Seqno, 20000237: v2 with 0x237 session ID (key) +OVS_WAIT_UNTIL([test `ovs-pcap p0.pcap | grep 100022eb0000000120000237 | wc -l` -ge 1]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([tunnel_push_pop - action]) OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 other-config:hwaddr=aa:55:aa:55:00:00]) diff --git a/tests/tunnel.at b/tests/tunnel.at index 3c217b344f9b..654cdde364aa 100644 --- a/tests/tunnel.at +++ b/tests/tunnel.at @@ -406,6 +406,18 @@ AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl OVS_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([tunnel - ERSPAN]) +OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=erspan \ + options:remote_ip=1.1.1.1 ofport_request=1]) + +AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl + br0 65534/100: (dummy-internal) + p1 1/1: (erspan: remote_ip=1.1.1.1) +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([tunnel - different VXLAN UDP port]) OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=vxlan \ options:remote_ip=1.1.1.1 ofport_request=1 options:dst_port=4341]) diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml index 48554c0d2243..7641c432b90b 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -2602,6 +2602,40 @@ + +

    + Only erspan interfaces support these options. +

    + +

    + 20 bit index/port number associated with the ERSPAN traffic's + source port and direction (ingress/egress). This field is + platform dependent. +

    +
    + + +

    + ERSPAN version: 1 for version 1 (type II) + or 2 for version 2 (type III). +

    +
    + + +

    + Specifies the ERSPAN v2 mirrored traffic's direction. + 1 for egress traffic, and 0 for ingress traffic. +

    +
    + + +

    + ERSPAN hardware ID is a 6-bit unique identifier of an + ERSPAN v2 engine within a system. +

    +
    +
    +

    These options apply only to patch ports, that is, interfaces