From patchwork Tue Jun 27 18:11:33 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi-Hung Wei X-Patchwork-Id: 781325 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 3wxvD10k58z9s2s for ; Wed, 28 Jun 2017 04:12:49 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="JRD6ogXk"; dkim-atps=neutral Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 42519CC0; Tue, 27 Jun 2017 18:11:54 +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 E258FC9E for ; Tue, 27 Jun 2017 18:11:52 +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 272D320A for ; Tue, 27 Jun 2017 18:11:52 +0000 (UTC) Received: by mail-pg0-f67.google.com with SMTP id u62so5194966pgb.0 for ; Tue, 27 Jun 2017 11:11:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ZAycNOrFn51NWRtlZXm6wGXUkY/Je/vlSVT2sNogQ2A=; b=JRD6ogXk5YSsGwY6U0h7sjCIDy0CrpUnhv8iL6DMjURpTU4Oy+Vf3thcTv5Ekofueh yONytDxA308ky2MKCixqlaWZGqp4YRorpz1BQ9sewHZJrfXBiiDIPA+/PYhlE3q1J/v+ Q/631Z1GLF+7pviENulEwY47ymuiRjY+yae7RqHkFfPdrM0qrNxZGgvyJ9sxniloUZUn SwbAlWJoED8b3tViqrCuFcvBRQrR/IbPZGkI1daCzusWCw1r4x2l2maMU/4WPj66wPBA kMV639qao1bvQZvFBDiz5jzXDG4B6sq9a/nJ4jJTceHrHO8PQXLelslmaK/m8DXd06QN Az3w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ZAycNOrFn51NWRtlZXm6wGXUkY/Je/vlSVT2sNogQ2A=; b=jzLJhK6/CoXOb+YArWhABSLptABzO7E61E/8HSsgIJykYntXX3TMBVu8Kg9u+0eSIG C5/JCiJW94Do2rRgzSvS3EMVLfffQQFxPNSsTSsX3LGRX/zmXxvGbciG5lbG1r0rBRWo mUiqYbh2RIj+Kvs9txBhwqH6HRji9Ym0Bkd7zTjTRCJPRUzYDK/tGddIs6uwcE1XBPC1 G/8pWuB5/KhAmQqsF8Mcg9UjjhpTLJWKAGb+0Z4ANf0vT+Bh7pGG83/QfBBYcWZwEDyJ rYFSAwdPub8/Kp0UCVs7a6hWmk/SLBO2b9f+fIqmq4bYRekWm7DutG5aUNcR0cIZt72Y xuxg== X-Gm-Message-State: AKS2vOxa1Pf89CcXw3ANLvS89evDLw0m0DRCegGDRCokWsio/D6hZ4lj okjxTxDsMmdYOOLyI7U= X-Received: by 10.99.94.70 with SMTP id s67mr6452114pgb.82.1498587111417; Tue, 27 Jun 2017 11:11:51 -0700 (PDT) Received: from sc9-mailhost3.vmware.com ([208.91.1.34]) by smtp.gmail.com with ESMTPSA id j14sm7350852pgt.7.2017.06.27.11.11.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 27 Jun 2017 11:11:51 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Tue, 27 Jun 2017 11:11:33 -0700 Message-Id: <1498587094-107805-3-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1498587094-107805-1-git-send-email-yihung.wei@gmail.com> References: <1498587094-107805-1-git-send-email-yihung.wei@gmail.com> X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, RCVD_IN_SORBS_SPAM 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 v3 2/3] ofproto/trace: Add support for tracing conntrack recirculation 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 Previously, a user need to run ofproto/trace multiple times to derive the final datapath actions if a flow hit conntrack actions that involves recirculation. To improve the usability of ofproto/trace, in this patch, we keep track of the conntrack actions, and automatically run the recirculation process so that a user only need to execute the ofproto/trace command once. Currently, this patch sets the default ct_state as trk and new in the automatic recirculation process. A following patch will provide an option to customize ct_state. Signed-off-by: Yi-Hung Wei --- ofproto/ofproto-dpif-rid.c | 13 +++++++ ofproto/ofproto-dpif-rid.h | 1 + ofproto/ofproto-dpif-trace.c | 88 +++++++++++++++++++++++++++++++++++++------- ofproto/ofproto-dpif-trace.h | 22 +++++++++++ ofproto/ofproto-dpif-xlate.c | 29 +++++++++++++-- ofproto/ofproto-dpif-xlate.h | 4 ++ tests/ofproto-dpif.at | 35 ++++++++++++++++++ 7 files changed, 175 insertions(+), 17 deletions(-) diff --git a/ofproto/ofproto-dpif-rid.c b/ofproto/ofproto-dpif-rid.c index 9381dee61404..d546b150b938 100644 --- a/ofproto/ofproto-dpif-rid.c +++ b/ofproto/ofproto-dpif-rid.c @@ -107,6 +107,19 @@ recirc_id_node_find(uint32_t id) : NULL; } +bool +recirc_id_node_find_and_ref(uint32_t id) +{ + struct recirc_id_node *rid_node = + CONST_CAST(struct recirc_id_node *, recirc_id_node_find(id)); + + if (!rid_node) { + return false; + } + + return ovs_refcount_try_ref_rcu(&rid_node->refcount); +} + static uint32_t frozen_state_hash(const struct frozen_state *state) { diff --git a/ofproto/ofproto-dpif-rid.h b/ofproto/ofproto-dpif-rid.h index ab9b1b7e5222..c6743a133ed5 100644 --- a/ofproto/ofproto-dpif-rid.h +++ b/ofproto/ofproto-dpif-rid.h @@ -186,6 +186,7 @@ void recirc_free_id(uint32_t recirc_id); void recirc_free_ofproto(struct ofproto_dpif *, const char *ofproto_name); const struct recirc_id_node *recirc_id_node_find(uint32_t recirc_id); +bool recirc_id_node_find_and_ref(uint32_t id); static inline struct recirc_id_node * recirc_id_node_from_state(const struct frozen_state *state) diff --git a/ofproto/ofproto-dpif-trace.c b/ofproto/ofproto-dpif-trace.c index 56bf93075636..362f932a23a7 100644 --- a/ofproto/ofproto-dpif-trace.c +++ b/ofproto/ofproto-dpif-trace.c @@ -86,6 +86,38 @@ oftrace_node_destroy(struct oftrace_node *node) } } +bool +oftrace_add_recirc_node(struct ovs_list *recirc_queue, + enum oftrace_recirc_type type, struct flow *flow, + uint32_t recirc_id) +{ + if (type != OFT_RECIRC_INIT) { + if (!recirc_id_node_find_and_ref(recirc_id)) { + return false; + } + } + + struct oftrace_recirc_node *node = xmalloc(sizeof *node); + ovs_list_push_back(recirc_queue, &node->node); + + node->type = type; + node->recirc_id = recirc_id; + node->flow = xmemdup(flow, sizeof *flow); + node->flow->recirc_id = recirc_id; + + return true; +} + +static void +oftrace_recirc_node_destroy(struct oftrace_recirc_node *node) +{ + if (node->type != OFT_RECIRC_INIT) { + recirc_free_id(node->recirc_id); + } + free(node->flow); + free(node); +} + static void oftrace_node_print_details(struct ds *output, const struct ovs_list *nodes, int level) @@ -419,20 +451,11 @@ exit: ofpbuf_uninit(&ofpacts); } -/* Implements a "trace" through 'ofproto''s flow table, appending a textual - * description of the results to 'output'. - * - * The trace follows a packet with the specified 'flow' through the flow - * table. 'packet' may be nonnull to trace an actual packet, with consequent - * side effects (if it is nonnull then its flow must be 'flow'). - * - * If 'ofpacts' is nonnull then its 'ofpacts_len' bytes specify the actions to - * trace, otherwise the actions are determined by a flow table lookup. */ static void -ofproto_trace(struct ofproto_dpif *ofproto, struct flow *flow, - const struct dp_packet *packet, - const struct ofpact ofpacts[], size_t ofpacts_len, - struct ds *output) +ofproto_trace__(struct ofproto_dpif *ofproto, struct flow *flow, + const struct dp_packet *packet, struct ovs_list *recirc_queue, + const struct ofpact ofpacts[], size_t ofpacts_len, + struct ds *output) { struct ofpbuf odp_actions; ofpbuf_init(&odp_actions, 0); @@ -447,6 +470,7 @@ ofproto_trace(struct ofproto_dpif *ofproto, struct flow *flow, xin.ofpacts = ofpacts; xin.ofpacts_len = ofpacts_len; xin.trace = &trace; + xin.recirc_queue = recirc_queue; /* Copy initial flow out of xin.flow. It differs from '*flow' because * xlate_in_init() initializes actset_output to OFPP_UNSET. */ @@ -503,6 +527,44 @@ ofproto_trace(struct ofproto_dpif *ofproto, struct flow *flow, oftrace_node_list_destroy(&trace); } +/* Implements a "trace" through 'ofproto''s flow table, appending a textual + * description of the results to 'output'. + * + * The trace follows a packet with the specified 'flow' through the flow + * table. 'packet' may be nonnull to trace an actual packet, with consequent + * side effects (if it is nonnull then its flow must be 'flow'). + * + * If 'ofpacts' is nonnull then its 'ofpacts_len' bytes specify the actions to + * trace, otherwise the actions are determined by a flow table lookup. */ +static void +ofproto_trace(struct ofproto_dpif *ofproto, struct flow *flow, + const struct dp_packet *packet, + const struct ofpact ofpacts[], size_t ofpacts_len, + struct ds *output) +{ + struct ovs_list recirc_queue = OVS_LIST_INITIALIZER(&recirc_queue); + oftrace_add_recirc_node(&recirc_queue, OFT_RECIRC_INIT, flow, + flow->recirc_id); + + while (!ovs_list_is_empty(&recirc_queue)) { + struct ovs_list *node = ovs_list_pop_front(&recirc_queue); + struct oftrace_recirc_node *recirc_node; + + ASSIGN_CONTAINER(recirc_node, node, node); + + if (recirc_node->type == OFT_RECIRC_CONNTRACK) { + recirc_node->flow->ct_state = CS_TRACKED | CS_NEW; + ds_put_cstr(output, "\n\nResume conntrack prcessing with " + "default ct_state=trk|new.\n"); + ds_put_char_multiple(output, '-', 79); + ds_put_char(output, '\n'); + } + ofproto_trace__(ofproto, recirc_node->flow, packet, &recirc_queue, + ofpacts, ofpacts_len, output); + oftrace_recirc_node_destroy(recirc_node); + } +} + void ofproto_dpif_trace_init(void) { diff --git a/ofproto/ofproto-dpif-trace.h b/ofproto/ofproto-dpif-trace.h index e3d3b393cec8..db3be290e477 100644 --- a/ofproto/ofproto-dpif-trace.h +++ b/ofproto/ofproto-dpif-trace.h @@ -45,6 +45,16 @@ enum oftrace_node_type { OFT_ERROR, /* An erroneous situation, worth logging. */ }; +/* Type of a node within a recirculation queue. */ +enum oftrace_recirc_type { + /* The initial flow to be traced. */ + OFT_RECIRC_INIT, + /* A flow recirculates because of the following actions. */ + OFT_RECIRC_CONNTRACK, + OFT_RECIRC_MPLS, + OFT_RECIRC_BOND, +}; + /* A node within a trace. */ struct oftrace_node { struct ovs_list node; /* In parent. */ @@ -54,9 +64,21 @@ struct oftrace_node { char *text; }; +/* A node within a recirculation queue. */ +struct oftrace_recirc_node { + struct ovs_list node; /* In recirc_queue. */ + + enum oftrace_recirc_type type; + uint32_t recirc_id; + struct flow *flow; +}; + void ofproto_dpif_trace_init(void); struct oftrace_node *oftrace_report(struct ovs_list *, enum oftrace_node_type, const char *text); +bool oftrace_add_recirc_node(struct ovs_list *recirc_queue, + enum oftrace_recirc_type, struct flow *, + uint32_t recirc_id); #endif /* ofproto-dpif-trace.h */ diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 48c4bad4ac0b..c29d37e3187c 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -4356,9 +4356,14 @@ emit_continuation(struct xlate_ctx *ctx, const struct frozen_state *state) } } -static void +/* Creates a frozen state, and allocates a unique recirc id for the given + * state. Returns a non-zero recirc id if it is allocated successfully. + * Returns 0 otherwise. + **/ +static uint32_t finish_freezing__(struct xlate_ctx *ctx, uint8_t table) { + uint32_t id = 0; ovs_assert(ctx->freezing); struct frozen_state state = { @@ -4385,11 +4390,11 @@ finish_freezing__(struct xlate_ctx *ctx, uint8_t table) * recirculation context, will be returned if possible. * The life-cycle of this recirc id is managed by associating it * with the udpif key ('ukey') created for each new datapath flow. */ - uint32_t id = recirc_alloc_id_ctx(&state); + id = recirc_alloc_id_ctx(&state); if (!id) { xlate_report_error(ctx, "Failed to allocate recirculation id"); ctx->error = XLATE_NO_RECIRCULATION_CONTEXT; - return; + return 0; } recirc_refs_add(&ctx->xout->recircs, id); @@ -4408,6 +4413,7 @@ finish_freezing__(struct xlate_ctx *ctx, uint8_t table) /* Undo changes done by freezing. */ ctx_cancel_freeze(ctx); + return id; } /* Called only when we're freezing. */ @@ -4425,8 +4431,22 @@ finish_freezing(struct xlate_ctx *ctx) static void compose_recirculate_and_fork(struct xlate_ctx *ctx, uint8_t table) { + uint32_t recirc_id; ctx->freezing = true; - finish_freezing__(ctx, table); + recirc_id = finish_freezing__(ctx, table); + + if (OVS_UNLIKELY(ctx->xin->trace) && recirc_id) { + if (oftrace_add_recirc_node(ctx->xin->recirc_queue, + OFT_RECIRC_CONNTRACK, &ctx->xin->flow, + recirc_id)) { + xlate_report(ctx, OFT_DETAIL, "A clone of the packet is forked to " + "recirculate. The forked pipeline will be resumed at " + "table %u.", table); + } else { + xlate_report(ctx, OFT_DETAIL, "Failed to trace the conntrack " + "forked pipeline with recirc_id = %d.", recirc_id); + } + } } static void @@ -5970,6 +5990,7 @@ xlate_in_init(struct xlate_in *xin, struct ofproto_dpif *ofproto, xin->wc = wc; xin->odp_actions = odp_actions; xin->in_packet_out = false; + xin->recirc_queue = NULL; /* Do recirc lookup. */ xin->frozen_state = NULL; diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h index 68e114afb9ae..3de7dec8765d 100644 --- a/ofproto/ofproto-dpif-xlate.h +++ b/ofproto/ofproto-dpif-xlate.h @@ -158,6 +158,10 @@ struct xlate_in { /* If true, the packet to be translated is from a packet_out msg. */ bool in_packet_out; + + /* ofproto/trace maintains this queue to trace flows that require + * recirculation. */ + struct ovs_list *recirc_queue; }; void xlate_ofproto_set(struct ofproto_dpif *, const char *name, struct dpif *, diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index e2228661fd09..d28f135b4d60 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -9710,6 +9710,41 @@ udp,vlan_tci=0x0000,dl_src=50:54:00:00:00:0a,dl_dst=50:54:00:00:00:09,nw_src=10. OVS_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([ofproto-dpif - conntrack - ofproto/trace]) +OVS_VSWITCHD_START + +add_of_ports br0 1 2 + +AT_DATA([flows.txt], [dnl +dnl Table 0 +dnl +table=0,priority=100,arp,action=normal +table=0,priority=10,udp,action=ct(table=1,zone=0) +table=0,priority=1,action=drop +dnl +dnl Table 1 +dnl +table=1,priority=10,in_port=1,ct_state=+trk+new,udp,action=ct(commit,zone=0),2 +table=1,priority=10,in_port=1,ct_state=+trk+est,udp,action=2 +table=1,priority=10,in_port=2,ct_state=+trk+est,udp,action=1 +table=1,priority=1,action=drop +]) + +AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) + +AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=2,udp'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: drop +]) + +AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,udp'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: ct(commit),2 +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([ofproto - set mtu]) OVS_VSWITCHD_START