From patchwork Tue Jul 4 09:46:38 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Chandran, Sugesh" X-Patchwork-Id: 783824 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org 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 3x1zgb6M2rz9s7B for ; Tue, 4 Jul 2017 19:47:23 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 9043D8D4; Tue, 4 Jul 2017 09:46:46 +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 5BC6F88A for ; Tue, 4 Jul 2017 09:46:44 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 7D03DCE for ; Tue, 4 Jul 2017 09:46:43 +0000 (UTC) Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 04 Jul 2017 02:46:43 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos; i="5.40,307,1496127600"; d="scan'208"; a="1167881878" Received: from silpixa00389820.ir.intel.com ([10.237.222.155]) by fmsmga001.fm.intel.com with ESMTP; 04 Jul 2017 02:46:41 -0700 From: Sugesh Chandran To: dev@openvswitch.org, azhou@ovn.org, joe@ovn.org Date: Tue, 4 Jul 2017 10:46:38 +0100 Message-Id: <1499161601-3230-2-git-send-email-sugesh.chandran@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1499161601-3230-1-git-send-email-sugesh.chandran@intel.com> References: <1499161601-3230-1-git-send-email-sugesh.chandran@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v2 1/4] xlate: Refactor translation of patch port output actions. 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: , Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Outputting to a patch port is translated by its peer patch port actions. Refactoring the translation part to use later in the patch series for the tunnel push. Signed-off-by: Sugesh Chandran Signed-off-by: Zoltán Balogh Co-authored-by: Zoltán Balogh --- ofproto/ofproto-dpif-xlate.c | 272 ++++++++++++++++++++++--------------------- 1 file changed, 138 insertions(+), 134 deletions(-) diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 1f4fe1d..b4323d4 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -426,6 +426,10 @@ static void xlate_action_set(struct xlate_ctx *ctx); static void xlate_commit_actions(struct xlate_ctx *ctx); static void +apply_nested_clone_actions(struct xlate_ctx *ctx, const struct xport *in_dev, + struct xport *out_dev); + +static void ctx_trigger_freeze(struct xlate_ctx *ctx) { ctx->exit = true; @@ -3258,6 +3262,138 @@ xlate_flow_is_protected(const struct xlate_ctx *ctx, const struct flow *flow, co xport_in->xbundle->protected && xport_out->xbundle->protected); } +/* Function to combine actions from following device/port with the current + * device actions in openflow pipeline. Mainly used for the translation of + * patch/tunnel port output actions. It pushes the openflow state into a stack + * first, clear out to execute the packet through the device and finally pop + * the openflow state back from the stack. This is equivalent to cloning + * a packet in translation for the duration of execution. + * + * On output to a patch port, the output action will be replaced with set of + * nested actions on the peer patch port. + * Similarly on output to a tunnel port, the post nested actions on + * tunnel are chained up with the tunnel-push action. + */ +static void +apply_nested_clone_actions(struct xlate_ctx *ctx, const struct xport *in_dev, + struct xport *out_dev) +{ + struct flow *flow = &ctx->xin->flow; + struct flow old_flow = ctx->xin->flow; + struct flow_tnl old_flow_tnl_wc = ctx->wc->masks.tunnel; + bool old_conntrack = ctx->conntracked; + bool old_was_mpls = ctx->was_mpls; + ovs_version_t old_version = ctx->xin->tables_version; + struct ofpbuf old_stack = ctx->stack; + uint8_t new_stack[1024]; + struct ofpbuf old_action_set = ctx->action_set; + struct ovs_list *old_trace = ctx->xin->trace; + uint64_t actset_stub[1024 / 8]; + + ofpbuf_use_stub(&ctx->stack, new_stack, sizeof new_stack); + ofpbuf_use_stub(&ctx->action_set, actset_stub, sizeof actset_stub); + flow->in_port.ofp_port = out_dev->ofp_port; + flow->metadata = htonll(0); + memset(&flow->tunnel, 0, sizeof flow->tunnel); + flow->tunnel.metadata.tab = + ofproto_get_tun_tab(&out_dev->xbridge->ofproto->up); + ctx->wc->masks.tunnel.metadata.tab = flow->tunnel.metadata.tab; + memset(flow->regs, 0, sizeof flow->regs); + flow->actset_output = OFPP_UNSET; + clear_conntrack(ctx); + ctx->xin->trace = xlate_report(ctx, OFT_BRIDGE, + "bridge(\"%s\")", + out_dev->xbridge->name); + mirror_mask_t old_mirrors = ctx->mirrors; + bool independent_mirrors = out_dev->xbridge != ctx->xbridge; + if (independent_mirrors) { + ctx->mirrors = 0; + } + ctx->xbridge = out_dev->xbridge; + + /* The bridge is now known so obtain its table version. */ + ctx->xin->tables_version + = ofproto_dpif_get_tables_version(ctx->xbridge->ofproto); + + if (!process_special(ctx, out_dev) && may_receive(out_dev, ctx)) { + if (xport_stp_forward_state(out_dev) && + xport_rstp_forward_state(out_dev)) { + xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true, + false); + if (!ctx->freezing) { + xlate_action_set(ctx); + } + if (ctx->freezing) { + finish_freezing(ctx); + } + } else { + /* Forwarding is disabled by STP and RSTP. Let OFPP_NORMAL and + * the learning action look at the packet, then drop it. */ + struct flow old_base_flow = ctx->base_flow; + size_t old_size = ctx->odp_actions->size; + mirror_mask_t old_mirrors2 = ctx->mirrors; + + xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true, + false); + ctx->mirrors = old_mirrors2; + ctx->base_flow = old_base_flow; + ctx->odp_actions->size = old_size; + + /* Undo changes that may have been done for freezing. */ + ctx_cancel_freeze(ctx); + } + } + + ctx->xin->trace = old_trace; + if (independent_mirrors) { + ctx->mirrors = old_mirrors; + } + ctx->xin->flow = old_flow; + ctx->xbridge = in_dev->xbridge; + ofpbuf_uninit(&ctx->action_set); + ctx->action_set = old_action_set; + ofpbuf_uninit(&ctx->stack); + ctx->stack = old_stack; + + /* Restore calling bridge's lookup version. */ + ctx->xin->tables_version = old_version; + + /* Restore to calling bridge tunneling information */ + ctx->wc->masks.tunnel = old_flow_tnl_wc; + + /* The out bridge popping MPLS should have no effect on the original + * bridge. */ + ctx->was_mpls = old_was_mpls; + + /* The out bridge's conntrack execution should have no effect on the + * original bridge. */ + ctx->conntracked = old_conntrack; + + /* The fact that the out bridge exits (for any reason) does not mean + * that the original bridge should exit. Specifically, if the out + * bridge freezes translation, the original bridge must continue + * processing with the original, not the frozen packet! */ + ctx->exit = false; + + /* Out bridge errors do not propagate back. */ + ctx->error = XLATE_OK; + + if (ctx->xin->resubmit_stats) { + netdev_vport_inc_tx(in_dev->netdev, ctx->xin->resubmit_stats); + netdev_vport_inc_rx(out_dev->netdev, ctx->xin->resubmit_stats); + if (out_dev->bfd) { + bfd_account_rx(out_dev->bfd, ctx->xin->resubmit_stats); + } + } + if (ctx->xin->xcache) { + struct xc_entry *entry; + entry = xlate_cache_add_entry(ctx->xin->xcache, XC_NETDEV); + entry->dev.tx = netdev_ref(in_dev->netdev); + entry->dev.rx = netdev_ref(out_dev->netdev); + entry->dev.bfd = bfd_ref(out_dev->bfd); + } +} + static bool check_output_prerequisites(struct xlate_ctx *ctx, const struct xport *xport, @@ -3370,140 +3506,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, } if (xport->peer) { - const struct xport *peer = xport->peer; - struct flow old_flow = ctx->xin->flow; - struct flow_tnl old_flow_tnl_wc = ctx->wc->masks.tunnel; - bool old_conntrack = ctx->conntracked; - bool old_was_mpls = ctx->was_mpls; - ovs_version_t old_version = ctx->xin->tables_version; - struct ofpbuf old_stack = ctx->stack; - uint8_t new_stack[1024]; - struct ofpbuf old_action_set = ctx->action_set; - struct ovs_list *old_trace = ctx->xin->trace; - uint64_t actset_stub[1024 / 8]; - - ofpbuf_use_stub(&ctx->stack, new_stack, sizeof new_stack); - ofpbuf_use_stub(&ctx->action_set, actset_stub, sizeof actset_stub); - flow->in_port.ofp_port = peer->ofp_port; - flow->metadata = htonll(0); - memset(&flow->tunnel, 0, sizeof flow->tunnel); - flow->tunnel.metadata.tab = ofproto_get_tun_tab( - &peer->xbridge->ofproto->up); - ctx->wc->masks.tunnel.metadata.tab = flow->tunnel.metadata.tab; - memset(flow->regs, 0, sizeof flow->regs); - flow->actset_output = OFPP_UNSET; - clear_conntrack(ctx); - ctx->xin->trace = xlate_report(ctx, OFT_BRIDGE, - "bridge(\"%s\")", peer->xbridge->name); - - /* When the patch port points to a different bridge, then the mirrors - * for that bridge clearly apply independently to the packet, so we - * reset the mirror bitmap to zero and then restore it after the packet - * returns. - * - * When the patch port points to the same bridge, this is more of a - * design decision: can mirrors be re-applied to the packet after it - * re-enters the bridge, or should we treat that as doubly mirroring a - * single packet? The former may be cleaner, since it respects the - * model in which a patch port is like a physical cable plugged from - * one switch port to another, but the latter may be less surprising to - * users. We take the latter choice, for now at least. (To use the - * former choice, hard-code 'independent_mirrors' to "true".) */ - mirror_mask_t old_mirrors = ctx->mirrors; - bool independent_mirrors = peer->xbridge != ctx->xbridge; - if (independent_mirrors) { - ctx->mirrors = 0; - } - ctx->xbridge = peer->xbridge; - - /* The bridge is now known so obtain its table version. */ - ctx->xin->tables_version - = ofproto_dpif_get_tables_version(ctx->xbridge->ofproto); - - if (!process_special(ctx, peer) && may_receive(peer, ctx)) { - if (xport_stp_forward_state(peer) && xport_rstp_forward_state(peer)) { - xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true, - false); - if (!ctx->freezing) { - xlate_action_set(ctx); - } - if (ctx->freezing) { - finish_freezing(ctx); - } - } else { - /* Forwarding is disabled by STP and RSTP. Let OFPP_NORMAL and - * the learning action look at the packet, then drop it. */ - struct flow old_base_flow = ctx->base_flow; - size_t old_size = ctx->odp_actions->size; - mirror_mask_t old_mirrors2 = ctx->mirrors; - - xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true, - false); - ctx->mirrors = old_mirrors2; - ctx->base_flow = old_base_flow; - ctx->odp_actions->size = old_size; - - /* Undo changes that may have been done for freezing. */ - ctx_cancel_freeze(ctx); - } - } - - ctx->xin->trace = old_trace; - if (independent_mirrors) { - ctx->mirrors = old_mirrors; - } - ctx->xin->flow = old_flow; - ctx->xbridge = xport->xbridge; - ofpbuf_uninit(&ctx->action_set); - ctx->action_set = old_action_set; - ofpbuf_uninit(&ctx->stack); - ctx->stack = old_stack; - - /* Restore calling bridge's lookup version. */ - ctx->xin->tables_version = old_version; - - /* Since this packet came in on a patch port (from the perspective of - * the peer bridge), it cannot have useful tunnel information. As a - * result, any wildcards generated on that tunnel also cannot be valid. - * The tunnel wildcards must be restored to their original version since - * the peer bridge uses a separate tunnel metadata table and therefore - * any generated wildcards will be garbage in the context of our - * metadata table. */ - ctx->wc->masks.tunnel = old_flow_tnl_wc; - - /* The peer bridge popping MPLS should have no effect on the original - * bridge. */ - ctx->was_mpls = old_was_mpls; - - /* The peer bridge's conntrack execution should have no effect on the - * original bridge. */ - ctx->conntracked = old_conntrack; - - /* The fact that the peer bridge exits (for any reason) does not mean - * that the original bridge should exit. Specifically, if the peer - * bridge freezes translation, the original bridge must continue - * processing with the original, not the frozen packet! */ - ctx->exit = false; - - /* Peer bridge errors do not propagate back. */ - ctx->error = XLATE_OK; - - if (ctx->xin->resubmit_stats) { - netdev_vport_inc_tx(xport->netdev, ctx->xin->resubmit_stats); - netdev_vport_inc_rx(peer->netdev, ctx->xin->resubmit_stats); - if (peer->bfd) { - bfd_account_rx(peer->bfd, ctx->xin->resubmit_stats); - } - } - if (ctx->xin->xcache) { - struct xc_entry *entry; - - entry = xlate_cache_add_entry(ctx->xin->xcache, XC_NETDEV); - entry->dev.tx = netdev_ref(xport->netdev); - entry->dev.rx = netdev_ref(peer->netdev); - entry->dev.bfd = bfd_ref(peer->bfd); - } - return; + apply_nested_clone_actions(ctx, xport, xport->peer); + return; } memcpy(flow_vlans, flow->vlans, sizeof flow_vlans);