diff options
author | Antonio Fischetti <antonio.fischetti@intel.com> | 2017-08-01 20:12:03 -0700 |
---|---|---|
committer | Ben Pfaff <blp@ovn.org> | 2017-08-02 10:18:55 -0700 |
commit | ded30c74b1e57af84416cdf6c5babd66b1f48ee6 (patch) | |
tree | 8cb8adf3c3320a4c743bc9fa6aa188f8bea61a8e | |
parent | 324459a39d17559d1adcb42b9d141b0288a75127 (diff) | |
download | openvswitch-ded30c74b1e57af84416cdf6c5babd66b1f48ee6.tar.gz |
dpctl: Add new 'ct-bkts' command.
With the command:
ovs-appctl dpctl/ct-bkts
shows the number of connections per bucket.
By using a threshold:
ovs-appctl dpctl/ct-bkts gt=N
for each bucket shows the number of connections when they
are greater than N.
Signed-off-by: Antonio Fischetti <antonio.fischetti@intel.com>
Signed-off-by: Bhanuprakash Bodireddy <bhanuprakash.bodireddy@intel.com>
Co-authored-by: Bhanuprakash Bodireddy <bhanuprakash.bodireddy@intel.com>
Signed-off-by: Darrell Ball <dlu998@gmail.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
-rw-r--r-- | lib/conntrack.c | 9 | ||||
-rw-r--r-- | lib/conntrack.h | 2 | ||||
-rw-r--r-- | lib/ct-dpif.c | 4 | ||||
-rw-r--r-- | lib/ct-dpif.h | 3 | ||||
-rw-r--r-- | lib/dpctl.c | 103 | ||||
-rw-r--r-- | lib/dpctl.man | 7 | ||||
-rw-r--r-- | lib/dpif-netdev.c | 4 | ||||
-rw-r--r-- | lib/dpif-netlink.c | 4 | ||||
-rw-r--r-- | lib/dpif-provider.h | 2 | ||||
-rw-r--r-- | lib/netlink-conntrack.c | 6 | ||||
-rw-r--r-- | lib/netlink-conntrack.h | 3 | ||||
-rw-r--r-- | tests/test-netlink-conntrack.c | 3 | ||||
-rw-r--r-- | utilities/ovs-dpctl.c | 1 |
13 files changed, 134 insertions, 17 deletions
diff --git a/lib/conntrack.c b/lib/conntrack.c index 554ea2bae..cce1f2ca5 100644 --- a/lib/conntrack.c +++ b/lib/conntrack.c @@ -1948,7 +1948,7 @@ conn_key_to_tuple(const struct conn_key *key, struct ct_dpif_tuple *tuple) static void conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry *entry, - long long now) + long long now, int bkt) { struct ct_l4_proto *class; long long expiration; @@ -1971,11 +1971,12 @@ conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry *entry, if (class->conn_get_protoinfo) { class->conn_get_protoinfo(conn, &entry->protoinfo); } + entry->bkt = bkt; } int conntrack_dump_start(struct conntrack *ct, struct conntrack_dump *dump, - const uint16_t *pzone) + const uint16_t *pzone, int *ptot_bkts) { memset(dump, 0, sizeof(*dump)); if (pzone) { @@ -1984,6 +1985,8 @@ conntrack_dump_start(struct conntrack *ct, struct conntrack_dump *dump, } dump->ct = ct; + *ptot_bkts = CONNTRACK_BUCKETS; + return 0; } @@ -2008,7 +2011,7 @@ conntrack_dump_next(struct conntrack_dump *dump, struct ct_dpif_entry *entry) INIT_CONTAINER(conn, node, node); if ((!dump->filter_zone || conn->key.zone == dump->zone) && (conn->conn_type != CT_CONN_TYPE_UN_NAT)) { - conn_to_ct_dpif_entry(conn, entry, now); + conn_to_ct_dpif_entry(conn, entry, now, dump->bucket); break; } /* Else continue, until we find an entry in the appropriate zone diff --git a/lib/conntrack.h b/lib/conntrack.h index defde4c5f..3f484442d 100644 --- a/lib/conntrack.h +++ b/lib/conntrack.h @@ -108,7 +108,7 @@ struct conntrack_dump { struct ct_dpif_entry; int conntrack_dump_start(struct conntrack *, struct conntrack_dump *, - const uint16_t *pzone); + const uint16_t *pzone, int *); int conntrack_dump_next(struct conntrack_dump *, struct ct_dpif_entry *); int conntrack_dump_done(struct conntrack_dump *); diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c index f8d2cf12f..c79e69e23 100644 --- a/lib/ct-dpif.c +++ b/lib/ct-dpif.c @@ -65,12 +65,12 @@ static const struct flags ct_dpif_status_flags[] = { * that represents the error. Otherwise it returns zero. */ int ct_dpif_dump_start(struct dpif *dpif, struct ct_dpif_dump_state **dump, - const uint16_t *zone) + const uint16_t *zone, int *ptot_bkts) { int err; err = (dpif->dpif_class->ct_dump_start - ? dpif->dpif_class->ct_dump_start(dpif, dump, zone) + ? dpif->dpif_class->ct_dump_start(dpif, dump, zone, ptot_bkts) : EOPNOTSUPP); if (!err) { diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h index cd35f3ece..d5f966175 100644 --- a/lib/ct-dpif.h +++ b/lib/ct-dpif.h @@ -169,6 +169,7 @@ struct ct_dpif_entry { /* Timeout for this entry in seconds */ uint32_t timeout; uint32_t mark; + uint32_t bkt; /* CT bucket number. */ }; enum { @@ -191,7 +192,7 @@ struct ct_dpif_dump_state { }; int ct_dpif_dump_start(struct dpif *, struct ct_dpif_dump_state **, - const uint16_t *zone); + const uint16_t *zone, int *); int ct_dpif_dump_next(struct ct_dpif_dump_state *, struct ct_dpif_entry *); int ct_dpif_dump_done(struct ct_dpif_dump_state *); int ct_dpif_flush(struct dpif *, const uint16_t *zone); diff --git a/lib/dpctl.c b/lib/dpctl.c index 6aa6c8e9e..59f09b7e5 100644 --- a/lib/dpctl.c +++ b/lib/dpctl.c @@ -1258,6 +1258,7 @@ dpctl_dump_conntrack(int argc, const char *argv[], struct ct_dpif_dump_state *dump; struct ct_dpif_entry cte; uint16_t zone, *pzone = NULL; + int tot_bkts; struct dpif *dpif; char *name; int error; @@ -1277,7 +1278,7 @@ dpctl_dump_conntrack(int argc, const char *argv[], return error; } - error = ct_dpif_dump_start(dpif, &dump, pzone); + error = ct_dpif_dump_start(dpif, &dump, pzone, &tot_bkts); if (error) { dpctl_error(dpctl_p, error, "starting conntrack dump"); dpif_close(dpif); @@ -1339,6 +1340,7 @@ dpctl_ct_stats_show(int argc, const char *argv[], struct ct_dpif_dump_state *dump; struct ct_dpif_entry cte; uint16_t zone, *pzone = NULL; + int tot_bkts; bool verbose = false; int lastargc = 0; @@ -1373,7 +1375,7 @@ dpctl_ct_stats_show(int argc, const char *argv[], 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); + error = ct_dpif_dump_start(dpif, &dump, pzone, &tot_bkts); if (error) { dpctl_error(dpctl_p, error, "starting conntrack dump"); dpif_close(dpif); @@ -1464,6 +1466,102 @@ dpctl_ct_stats_show(int argc, const char *argv[], dpif_close(dpif); return error; } + +#define CT_BKTS_GT "gt=" +static int +dpctl_ct_bkts(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 gt = 0; /* Threshold: display value when greater than gt. */ + uint16_t *pzone = NULL; + int tot_bkts = 0; + int error; + + if (argc > 1 && !strncmp(argv[argc - 1], CT_BKTS_GT, strlen(CT_BKTS_GT))) { + if (ovs_scan(argv[argc - 1], CT_BKTS_GT"%"SCNu16, >)) { + argc--; + } + } + + name = (argc == 2) ? 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; + } + + error = ct_dpif_dump_start(dpif, &dump, pzone, &tot_bkts); + if (error) { + dpctl_error(dpctl_p, error, "starting conntrack dump"); + dpif_close(dpif); + return error; + } + if (tot_bkts == -1) { + /* Command not available when called by kernel OvS. */ + dpctl_print(dpctl_p, + "Command is available for UserSpace ConnTracker only.\n"); + ct_dpif_dump_done(dump); + dpif_close(dpif); + return 0; + } + + dpctl_print(dpctl_p, "Total Buckets: %d\n", tot_bkts); + + int tot_conn = 0; + uint32_t *conn_per_bkts = xzalloc(tot_bkts * sizeof(uint32_t)); + + while (!ct_dpif_dump_next(dump, &cte)) { + ct_dpif_entry_uninit(&cte); + tot_conn++; + if (tot_bkts > 0) { + if (cte.bkt < tot_bkts) { + conn_per_bkts[cte.bkt]++; + } else { + dpctl_print(dpctl_p, "Bucket nr out of range: %d >= %d\n", + cte.bkt, tot_bkts); + } + } + } + + dpctl_print(dpctl_p, "Current Connections: %d\n", tot_conn); + dpctl_print(dpctl_p, "\n"); + if (tot_bkts && tot_conn) { + dpctl_print(dpctl_p, "+-----------+" + "-----------------------------------------+\n"); + dpctl_print(dpctl_p, "| Buckets |" + " Connections per Buckets |\n"); + dpctl_print(dpctl_p, "+-----------+" + "-----------------------------------------+"); +#define NUM_BKTS_DIPLAYED_PER_ROW 8 + for (int i = 0; i < tot_bkts; i++) { + if (i % NUM_BKTS_DIPLAYED_PER_ROW == 0) { + dpctl_print(dpctl_p, "\n %3d..%3d | ", + i, i + NUM_BKTS_DIPLAYED_PER_ROW - 1); + } + if (conn_per_bkts[i] > gt) { + dpctl_print(dpctl_p, "%5d", conn_per_bkts[i]); + } else { + dpctl_print(dpctl_p, "%5s", "."); + } + } + dpctl_print(dpctl_p, "\n\n"); + } + + ct_dpif_dump_done(dump); + dpif_close(dpif); + free(conn_per_bkts); + return error; +} /* Undocumented commands for unit testing. */ @@ -1760,6 +1858,7 @@ static const struct dpctl_command all_commands[] = { { "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 }, + { "ct-bkts", "[dp] [gt=N]", 0, 2, dpctl_ct_bkts, DP_RO }, { "help", "", 0, INT_MAX, dpctl_help, DP_RO }, { "list-commands", "", 0, INT_MAX, dpctl_list_commands, DP_RO }, diff --git a/lib/dpctl.man b/lib/dpctl.man index f95d54a81..675fe5af4 100644 --- a/lib/dpctl.man +++ b/lib/dpctl.man @@ -228,3 +228,10 @@ 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. +. +.TP +\*(DX\fBct\-bkts\fR [\fIdp\fR] [\fBgt=\fIThreshold\fR] +For each ConnTracker bucket, displays the number of connections used +by \fIdp\fR. +If \fBgt=\fIThreshold\fR is specified, bucket numbers are displayed when +the number of connections in a bucket is greater than \fIThreshold\fR. diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 284cecc74..e0af1792f 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -5437,7 +5437,7 @@ struct dp_netdev_ct_dump { static int dpif_netdev_ct_dump_start(struct dpif *dpif, struct ct_dpif_dump_state **dump_, - const uint16_t *pzone) + const uint16_t *pzone, int *ptot_bkts) { struct dp_netdev *dp = get_dp_netdev(dpif); struct dp_netdev_ct_dump *dump; @@ -5446,7 +5446,7 @@ dpif_netdev_ct_dump_start(struct dpif *dpif, struct ct_dpif_dump_state **dump_, dump->dp = dp; dump->ct = &dp->conntrack; - conntrack_dump_start(&dp->conntrack, &dump->dump, pzone); + conntrack_dump_start(&dp->conntrack, &dump->dump, pzone, ptot_bkts); *dump_ = &dump->up; diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index a75d25f8b..29001fbe4 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -2848,13 +2848,13 @@ struct dpif_netlink_ct_dump_state { static int dpif_netlink_ct_dump_start(struct dpif *dpif OVS_UNUSED, struct ct_dpif_dump_state **dump_, - const uint16_t *zone) + const uint16_t *zone, int *ptot_bkts) { struct dpif_netlink_ct_dump_state *dump; int err; dump = xzalloc(sizeof *dump); - err = nl_ct_dump_start(&dump->nl_ct_dump, zone); + err = nl_ct_dump_start(&dump->nl_ct_dump, zone, ptot_bkts); if (err) { free(dump); return err; diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h index 64ac2e2af..1d82a0939 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -419,7 +419,7 @@ struct dpif_class { * ct_dump_done() should perform any cleanup necessary (including * deallocating the 'state' structure, if applicable). */ int (*ct_dump_start)(struct dpif *, struct ct_dpif_dump_state **state, - const uint16_t *zone); + const uint16_t *zone, int *); int (*ct_dump_next)(struct dpif *, struct ct_dpif_dump_state *state, struct ct_dpif_entry *entry); int (*ct_dump_done)(struct dpif *, struct ct_dpif_dump_state *state); diff --git a/lib/netlink-conntrack.c b/lib/netlink-conntrack.c index f0e2aeac8..ac48b15bd 100644 --- a/lib/netlink-conntrack.c +++ b/lib/netlink-conntrack.c @@ -123,7 +123,8 @@ struct nl_ct_dump_state { /* Initialize a conntrack netlink dump. */ int -nl_ct_dump_start(struct nl_ct_dump_state **statep, const uint16_t *zone) +nl_ct_dump_start(struct nl_ct_dump_state **statep, const uint16_t *zone, + int *ptot_bkts) { struct nl_ct_dump_state *state; @@ -140,6 +141,9 @@ nl_ct_dump_start(struct nl_ct_dump_state **statep, const uint16_t *zone) nl_dump_start(&state->dump, NETLINK_NETFILTER, &state->buf); ofpbuf_clear(&state->buf); + /* Buckets to store connections are not used. */ + *ptot_bkts = -1; + return 0; } diff --git a/lib/netlink-conntrack.h b/lib/netlink-conntrack.h index 1263b2158..a95aa69a4 100644 --- a/lib/netlink-conntrack.h +++ b/lib/netlink-conntrack.h @@ -35,7 +35,8 @@ enum nl_ct_event_type { struct nl_ct_dump_state; -int nl_ct_dump_start(struct nl_ct_dump_state **, const uint16_t *zone); +int nl_ct_dump_start(struct nl_ct_dump_state **, const uint16_t *zone, + int *ptot_bkts); int nl_ct_dump_next(struct nl_ct_dump_state *, struct ct_dpif_entry *); int nl_ct_dump_done(struct nl_ct_dump_state *); diff --git a/tests/test-netlink-conntrack.c b/tests/test-netlink-conntrack.c index 000062d26..0d9dacee9 100644 --- a/tests/test-netlink-conntrack.c +++ b/tests/test-netlink-conntrack.c @@ -106,6 +106,7 @@ test_nl_ct_dump(struct ovs_cmdl_context *ctx) uint16_t zone, *pzone = NULL; struct ct_dpif_entry entry; int err; + int tot_bkts; if (ctx->argc >= 2) { if (!ovs_scan(ctx->argv[1], "zone=%"SCNu16, &zone)) { @@ -113,7 +114,7 @@ test_nl_ct_dump(struct ovs_cmdl_context *ctx) } pzone = &zone; } - err = nl_ct_dump_start(&dump, pzone); + err = nl_ct_dump_start(&dump, pzone, &tot_bkts); if (err) { ovs_fatal(err, "Error creating conntrack netlink dump"); } diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c index 7292fca3f..7b005ace3 100644 --- a/utilities/ovs-dpctl.c +++ b/utilities/ovs-dpctl.c @@ -202,6 +202,7 @@ usage(void *userdata OVS_UNUSED) "delete all conntrack entries in ZONE\n" " ct-stats-show [DP] [zone=ZONE] [verbose] " \ "CT connections grouped by protocol\n" + " ct-bkts [DP] [gt=N] display connections per CT bucket\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" |