]> git.proxmox.com Git - ovs.git/commitdiff
dpctl: Add new 'ct-bkts' command.
authorAntonio Fischetti <antonio.fischetti@intel.com>
Wed, 2 Aug 2017 03:12:03 +0000 (20:12 -0700)
committerBen Pfaff <blp@ovn.org>
Wed, 2 Aug 2017 17:18:55 +0000 (10:18 -0700)
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>
13 files changed:
lib/conntrack.c
lib/conntrack.h
lib/ct-dpif.c
lib/ct-dpif.h
lib/dpctl.c
lib/dpctl.man
lib/dpif-netdev.c
lib/dpif-netlink.c
lib/dpif-provider.h
lib/netlink-conntrack.c
lib/netlink-conntrack.h
tests/test-netlink-conntrack.c
utilities/ovs-dpctl.c

index 554ea2bae1bce1b017e2ab38d85b4b66edca5aaa..cce1f2ca5be313590ab3989a020e8875100d6af3 100644 (file)
@@ -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
index defde4c5fb2b1e4e993e31a00c7e079dd6964248..3f484442d7e9c28e130d3464ff90066cf130a165 100644 (file)
@@ -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 *);
 
index f8d2cf12f2889592f112df9980b0f0dff23c00fe..c79e69e239703af5e82e4a808f36a9ecbc7636c9 100644 (file)
@@ -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) {
index cd35f3ece80d43db74d9ef969b7a0d74a98da3d0..d5f966175bc00e851470a166fd97f0c83316c956 100644 (file)
@@ -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);
index 6aa6c8e9e2b0467716c2291732d55ecc4c4b94ab..59f09b7e51b9e5ef995a1ed4f73b122130ef68d2 100644 (file)
@@ -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, &gt)) {
+            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;
+}
 \f
 /* 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 },
 
index f95d54a81ac0130e302517871dfc23c83f94961e..675fe5af49141928b055336e654dd05063d0c81d 100644 (file)
@@ -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.
index 284cecc74753189eb910ed692319b4b10f3c4e0f..e0af1792f2b6452e6cf039986231a007ff9ceefd 100644 (file)
@@ -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;
 
index a75d25f8bace8aa5066c91811866df2c51888ea5..29001fbe4a549a2baeaf1061329c3afa8b2b4d62 100644 (file)
@@ -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;
index 64ac2e2af8f4e60f6b748ecfd8683c89178018b8..1d82a0939aa12f3586ee2e391fefca22f9928090 100644 (file)
@@ -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);
index f0e2aeac8e6290353fed3401bb9a7680ffd8ee51..ac48b15bde90c1e1fca7e6c267809d7632be8632 100644 (file)
@@ -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;
 }
 
index 1263b2158dbf0c6134e9b49deb1e9d463a61638b..a95aa69a4cdec68c52acfea6f64f462eb59d7b35 100644 (file)
@@ -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 *);
 
index 000062d267188fecf844a6cc1e742dbd4d61f9e2..0d9dacee910ab0fd814407725b00f0c43ef3e5ff 100644 (file)
@@ -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");
     }
index 7292fca3f4cce1484b6293b8916e491362cfdf5f..7b005ace3f4e0497c6c813d29f3daa1d246ac916 100644 (file)
@@ -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"