From patchwork Fri Jun 23 12:28:21 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Fischetti, Antonio" X-Patchwork-Id: 779976 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 3wvHn63DQFz9s8N for ; Fri, 23 Jun 2017 22:28:58 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id B9733B7C; Fri, 23 Jun 2017 12:28:28 +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 DBF10B76 for ; Fri, 23 Jun 2017 12:28:25 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 1F90C1DB for ; Fri, 23 Jun 2017 12:28:25 +0000 (UTC) Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 23 Jun 2017 05:28:24 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.39,378,1493708400"; d="scan'208";a="871025018" Received: from sivswdev01.ir.intel.com (HELO localhost.localdomain) ([10.237.217.45]) by FMSMGA003.fm.intel.com with ESMTP; 23 Jun 2017 05:28:24 -0700 From: antonio.fischetti@intel.com To: dev@openvswitch.org Date: Fri, 23 Jun 2017 13:28:21 +0100 Message-Id: <1498220902-27157-2-git-send-email-antonio.fischetti@intel.com> X-Mailer: git-send-email 1.7.0.7 In-Reply-To: <1498220902-27157-1-git-send-email-antonio.fischetti@intel.com> References: <1498220902-27157-1-git-send-email-antonio.fischetti@intel.com> X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_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 2/3] dpctl: add CT Stats for Connections per protocol. 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 From: Antonio Fischetti Adds CT stats to report number of connections grouped by protocol. By using utilities/ovs-appctl dpctl/ct-stats-show it can display something like: Connections Stats: Total: 1808 TCP: 1808 With the verbose options: utilities/ovs-appctl dpctl/ct-stats-show verbose it can display: Connections Stats: Total: 2671 TCP: 2671 Conn per TCP states: [ESTABLISHED]=1000 [CLOSING]=1 [TIME_WAIT]=1670 Signed-off-by: Antonio Fischetti Signed-off-by: Bhanuprakash Bodireddy Co-authored-by: Bhanuprakash Bodireddy --- lib/ct-dpif.c | 14 +++++ lib/ct-dpif.h | 18 ++++++- lib/dpctl.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++- lib/dpctl.man | 7 +++ utilities/ovs-dpctl.c | 2 + 5 files changed, 177 insertions(+), 2 deletions(-) diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c index 8f0b4ed..f8d2cf1 100644 --- a/lib/ct-dpif.c +++ b/lib/ct-dpif.c @@ -409,3 +409,17 @@ ct_dpif_format_helper(struct ds *ds, const char *title, ds_put_cstr(ds, helper->name); } } + +uint8_t +ct_dpif_coalesce_tcp_state(uint8_t state) +{ + return coalesce_tcp_state(state); +} + +void +ct_dpif_format_tcp_stat(struct ds * ds, int tcp_state, int conn_per_state) +{ + ct_dpif_format_enum(ds, "\t [", tcp_state, ct_dpif_tcp_state_string); + ds_put_cstr(ds, "]"); + ds_put_format(ds, "=%u", conn_per_state); +} diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h index e8e159a..cd35f3e 100644 --- a/lib/ct-dpif.h +++ b/lib/ct-dpif.h @@ -70,7 +70,8 @@ struct ct_dpif_timestamp { CT_DPIF_TCP_STATE(CLOSING) \ CT_DPIF_TCP_STATE(LAST_ACK) \ CT_DPIF_TCP_STATE(FIN_WAIT_2) \ - CT_DPIF_TCP_STATE(TIME_WAIT) + CT_DPIF_TCP_STATE(TIME_WAIT) \ + CT_DPIF_TCP_STATE(MAX_NUM) enum ct_dpif_tcp_state { #define CT_DPIF_TCP_STATE(STATE) CT_DPIF_TCPS_##STATE, @@ -170,6 +171,19 @@ struct ct_dpif_entry { uint32_t mark; }; +enum { + CT_STATS_UDP, + CT_STATS_TCP, + CT_STATS_SCTP, + CT_STATS_ICMP, + CT_STATS_ICMPV6, + CT_STATS_UDPLITE, + CT_STATS_DCCP, + CT_STATS_IGMP, + CT_STATS_OTHER, + CT_STATS_MAX, +}; + struct dpif; struct ct_dpif_dump_state { @@ -185,5 +199,7 @@ void ct_dpif_entry_uninit(struct ct_dpif_entry *); void ct_dpif_format_entry(const struct ct_dpif_entry *, struct ds *, bool verbose, bool print_stats); void ct_dpif_format_tuple(struct ds *, const struct ct_dpif_tuple *); +uint8_t ct_dpif_coalesce_tcp_state(uint8_t state); +void ct_dpif_format_tcp_stat(struct ds *, int, int); #endif /* CT_DPIF_H */ diff --git a/lib/dpctl.c b/lib/dpctl.c index cde5341..4cca9c8 100644 --- a/lib/dpctl.c +++ b/lib/dpctl.c @@ -1308,6 +1308,141 @@ dpctl_flush_conntrack(int argc, const char *argv[], dpif_close(dpif); return error; } + +static int +dpctl_ct_stats_show(int argc, const char *argv[], + struct dpctl_params *dpctl_p) +{ + struct dpif *dpif; + char *name; + + struct ct_dpif_dump_state *dump; + struct ct_dpif_entry cte; + uint16_t zone, *pzone = NULL; + bool verbose = false; + int lastargc = 0; + + int proto_stats[CT_STATS_MAX]; + int tcp_conn_per_states[CT_DPIF_TCPS_MAX_NUM]; + int error; + + while (argc > 1 && lastargc != argc) { + lastargc = argc; + if (!strncmp(argv[argc - 1], "verbose", 7)) { + verbose = true; + argc--; + } else if (!strncmp(argv[argc - 1], "zone=", 5)) { + if (ovs_scan(argv[argc - 1], "zone=%"SCNu16, &zone)) { + pzone = &zone; + argc--; + } + } + } + + name = (argc > 1) ? xstrdup(argv[1]) : get_one_dp(dpctl_p); + if (!name) { + return EINVAL; + } + + error = parsed_dpif_open(name, false, &dpif); + free(name); + if (error) { + dpctl_error(dpctl_p, error, "opening datapath"); + return error; + } + + memset(proto_stats, 0, sizeof(proto_stats)); + memset(tcp_conn_per_states, 0, sizeof(tcp_conn_per_states)); + error = ct_dpif_dump_start(dpif, &dump, pzone); + if (error) { + dpctl_error(dpctl_p, error, "starting conntrack dump"); + dpif_close(dpif); + return error; + } + + int tot_conn = 0; + while (!ct_dpif_dump_next(dump, &cte)) { + ct_dpif_entry_uninit(&cte); + tot_conn++; + switch (cte.tuple_orig.ip_proto) { + case IPPROTO_ICMP: + proto_stats[CT_STATS_ICMP]++; + break; + case IPPROTO_ICMPV6: + proto_stats[CT_STATS_ICMPV6]++; + break; + case IPPROTO_TCP: + proto_stats[CT_STATS_TCP]++; + uint8_t tcp_state; + /* We keep two separate tcp states, but we print just one. The Linux + * kernel connection tracker internally keeps only one state, so + * 'state_orig' and 'state_reply', will be the same. */ + tcp_state = MAX(cte.protoinfo.tcp.state_orig, cte.protoinfo.tcp.state_reply); + tcp_state = ct_dpif_coalesce_tcp_state(tcp_state); + tcp_conn_per_states[tcp_state]++; + break; + case IPPROTO_UDP: + proto_stats[CT_STATS_UDP]++; + break; + case IPPROTO_SCTP: + proto_stats[CT_STATS_SCTP]++; + break; + case IPPROTO_UDPLITE: + proto_stats[CT_STATS_UDPLITE]++; + break; + case IPPROTO_DCCP: + proto_stats[CT_STATS_DCCP]++; + break; + case IPPROTO_IGMP: + proto_stats[CT_STATS_IGMP]++; + break; + default: + proto_stats[CT_STATS_OTHER]++; + break; + } + } + + dpctl_print(dpctl_p, "Connections Stats:\n Total: %d\n", tot_conn); + if (proto_stats[CT_STATS_TCP]) { + dpctl_print(dpctl_p, "\tTCP: %d\n", proto_stats[CT_STATS_TCP]); + if (verbose) { + dpctl_print(dpctl_p, "\t Conn per TCP states:\n"); + for (int i = 0; i < CT_DPIF_TCPS_MAX_NUM; i++) { + if (tcp_conn_per_states[i]) { + struct ds s = DS_EMPTY_INITIALIZER; + ct_dpif_format_tcp_stat(&s, i, tcp_conn_per_states[i]); + dpctl_print(dpctl_p, "%s\n", ds_cstr(&s)); + ds_destroy(&s); + } + } + } + } + if (proto_stats[CT_STATS_UDP]) { + dpctl_print(dpctl_p, "\tUDP: %d\n", proto_stats[CT_STATS_UDP]); + } + if (proto_stats[CT_STATS_UDPLITE]) { + dpctl_print(dpctl_p, "\tUDPLITE: %d\n", proto_stats[CT_STATS_UDPLITE]); + } + if (proto_stats[CT_STATS_SCTP]) { + dpctl_print(dpctl_p, "\tSCTP: %d\n", proto_stats[CT_STATS_SCTP]); + } + if (proto_stats[CT_STATS_ICMP]) { + dpctl_print(dpctl_p, "\tICMP: %d\n", proto_stats[CT_STATS_ICMP]); + } + if (proto_stats[CT_STATS_DCCP]) { + dpctl_print(dpctl_p, "\tDCCP: %d\n", proto_stats[CT_STATS_DCCP]); + } + if (proto_stats[CT_STATS_IGMP]) { + dpctl_print(dpctl_p, "\tIGMP: %d\n", proto_stats[CT_STATS_IGMP]); + } + if (proto_stats[CT_STATS_OTHER]) { + dpctl_print(dpctl_p, "\tOther: %d\n", proto_stats[CT_STATS_OTHER]); + } + + ct_dpif_dump_done(dump); + dpif_close(dpif); + return error; +} /* Undocumented commands for unit testing. */ @@ -1602,6 +1737,8 @@ static const struct dpctl_command all_commands[] = { { "del-flows", "[dp]", 0, 1, dpctl_del_flows, DP_RW }, { "dump-conntrack", "[dp] [zone=N]", 0, 2, dpctl_dump_conntrack, DP_RO }, { "flush-conntrack", "[dp] [zone=N]", 0, 2, dpctl_flush_conntrack, DP_RW }, + { "ct-stats-show", "[dp] [zone=N] [verbose]", + 0, 3, dpctl_ct_stats_show, DP_RO }, { "help", "", 0, INT_MAX, dpctl_help, DP_RO }, { "list-commands", "", 0, INT_MAX, dpctl_list_commands, DP_RO }, @@ -1625,7 +1762,6 @@ int dpctl_run_command(int argc, const char *argv[], struct dpctl_params *dpctl_p) { const struct dpctl_command *p; - if (argc < 1) { dpctl_error(dpctl_p, 0, "missing command name; use --help for help"); return EINVAL; diff --git a/lib/dpctl.man b/lib/dpctl.man index f6e4a7a..cccc574 100644 --- a/lib/dpctl.man +++ b/lib/dpctl.man @@ -220,3 +220,10 @@ added to the output. Flushes all the connection entries in the tracker used by \fIdp\fR. If \fBzone=\fIzone\fR is specified, only flushes the connections in \fBzone\fR. +. +.TP +\*(DX\fBct\-stats\-show\fR [\fIdp\fR] [\fBzone=\fIzone\fR] [\fBverbose\fR] +Displays the number of connections grouped by protocol used by \fIdp\fR. +If \fBzone=\fIzone\fR is specified, numbers refer to the connections in +\fBzone\fR. The \fBverbose\fR option allows to group by connection state +for each protocol. diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c index 1cc92f5..ea75c0c 100644 --- a/utilities/ovs-dpctl.c +++ b/utilities/ovs-dpctl.c @@ -181,6 +181,8 @@ usage(void *userdata OVS_UNUSED) "display conntrack entries for ZONE\n" " flush-conntrack [DP] [zone=ZONE] " \ "delete all conntrack entries in ZONE\n" + " ct-stats-show [DP] [zone=ZONE] [verbose] " \ + "CT connections grouped by protocol\n" "Each IFACE on add-dp, add-if, and set-if may be followed by\n" "comma-separated options. See ovs-dpctl(8) for syntax, or the\n" "Interface table in ovs-vswitchd.conf.db(5) for an options list.\n"