dpctl: Add dp-dump-flows, dp-dump-groups commands.
authorBen Pfaff <blp@nicira.com>
Fri, 13 Mar 2009 23:03:42 +0000 (16:03 -0700)
committerBen Pfaff <blp@nicira.com>
Fri, 13 Mar 2009 23:03:42 +0000 (16:03 -0700)
These should make it easier to debug datapath-related problems.

utilities/dpctl.8.in
utilities/dpctl.c

index bf62c7b32b6cefc72045af19f84648c887236fe9..e421aa2557d168b78ce8277d24a86412dc0f84aa 100644 (file)
@@ -100,6 +100,26 @@ If one or more datapaths are specified, information on only those
 datapaths are displayed.  Otherwise, \fBdpctl\fR displays information
 about all configured datapaths.
 
+.IP "\fBdp-dump-flows \fIdp\fR"
+Prints to the console all flow entries in datapath \fIdp\fR's
+flow table.
+
+This command is primarily useful for debugging the OpenFlow reference
+implementation.  The flow table entries that it displays are not
+OpenFlow flow entries.  Instead, they are different and considerably
+simpler flows maintained by the datapaths used by the OpenFlow
+reference implementation.
+
+.IP "\fBdp-dump-groups \fIdp\fR"
+Prints to the console the sets of port groups maintained by datapath
+\fIdp\fR.  Ordinarily there are at least 2 port groups in a datapath
+that \fBsecchan\fR or \fBvswitch\fR is controlling: group 0 contains
+all ports except those disabled by STP, and group 1 contains all
+ports.  Additional groups might be used in the future.
+
+This command is primarily useful for debugging the OpenFlow reference
+implementation.  OpenFlow does not have a concept of port groups.
+
 .SS "OpenFlow Switch Management Commands"
 
 These commands allow \fBdpctl\fR to monitor and administer an OpenFlow
index 053e8e0a11466efe97d736d62b64a5a2cb61a51b..f66f9219fe3be0e182ec043fb5c390028c6db98d 100644 (file)
 #include "command-line.h"
 #include "compiler.h"
 #include "dpif.h"
+#include "dynamic-string.h"
 #include "netdev.h"
 #include "netlink.h"
+#include "odp-util.h"
 #include "ofp-print.h"
 #include "ofpbuf.h"
 #include "openflow/nicira-ext.h"
@@ -215,6 +217,8 @@ usage(void)
            "  delif DP IFACE...           delete each IFACE from DP\n"
            "  showdp                      show basic info on all datapaths\n"
            "  showdp DP...                show basic info on each DP\n"
+           "  dp-dump-flows DP            display flows in DP\n"
+           "  dp-dump-groups DP           display port groups in DP\n"
            "\nFor OpenFlow switches:\n"
            "  show SWITCH                 show OpenFlow information\n"
            "  status SWITCH [KEY]         report statistics (about KEY)\n"
@@ -465,10 +469,24 @@ static void
 show_dpif(struct dpif *dpif)
 {
     struct odp_port *ports;
+    struct odp_stats stats;
     size_t n_ports;
     size_t i;
 
     printf("dp%u:\n", dpif_id(dpif));
+    if (!dpif_get_dp_stats(dpif, &stats)) {
+        printf("\tflows: cur:%"PRIu32", soft-max:%"PRIu32", "
+               "hard-max:%"PRIu32"\n",
+               stats.n_flows, stats.cur_capacity, stats.max_capacity);
+        printf("\tports: cur:%"PRIu32", max:%"PRIu32"\n",
+               stats.n_ports, stats.max_ports);
+        printf("\tgroups: max:%"PRIu16"\n", stats.max_groups);
+        printf("\tlookups: frags:%"PRIu64", hit:%"PRIu64", missed:%"PRIu64", "
+               "lost:%"PRIu64"\n",
+               stats.n_frags, stats.n_hit, stats.n_missed, stats.n_lost);
+        printf("\tqueues: max-miss:%"PRIu16", max-action:%"PRIu16"\n",
+               stats.max_miss_queue, stats.max_action_queue);
+    }
     query_ports(dpif, &ports, &n_ports);
     for (i = 0; i < n_ports; i++) {
         printf("\tport %u: %s\n", ports[i].port, ports[i].devname);
@@ -518,6 +536,64 @@ do_show_dp(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
     }
 }
 
+static void
+do_dp_dump_flows(const struct settings *s UNUSED,
+                 int argc UNUSED, char *argv[])
+{
+    struct odp_flow *flows;
+    struct dpif dpif;
+    size_t n_flows;
+    struct ds ds;
+    size_t i;
+
+    run(dpif_open(argv[1], &dpif), "opening datapath");
+    run(dpif_flow_list_all(&dpif, &flows, &n_flows), "listing all flows");
+
+    ds_init(&ds);
+    for (i = 0; i < n_flows; i++) {
+        struct odp_flow *f = &flows[i];
+        enum { MAX_ACTIONS = 4096 / sizeof(union odp_action) };
+        union odp_action actions[MAX_ACTIONS];
+
+        f->actions = actions;
+        f->n_actions = MAX_ACTIONS;
+        dpif_flow_query(&dpif, f);
+
+        ds_clear(&ds);
+        format_odp_flow(&ds, f);
+        printf("%s\n", ds_cstr(&ds));
+    }
+    ds_destroy(&ds);
+    dpif_close(&dpif);
+}
+
+static void
+do_dp_dump_groups(const struct settings *s UNUSED,
+                  int argc UNUSED, char *argv[])
+{
+    struct odp_stats stats;
+    struct dpif dpif;
+    unsigned int i;
+
+    run(dpif_open(argv[1], &dpif), "opening datapath");
+    run(dpif_get_dp_stats(&dpif, &stats), "get datapath stats");
+    for (i = 0; i < stats.max_groups; i++) {
+        uint16_t ports[UINT16_MAX];
+        size_t n_ports;
+
+        if (!dpif_port_group_get(&dpif, i, ports,
+                                 ARRAY_SIZE(ports), &n_ports) && n_ports) {
+            size_t j;
+
+            printf("group %u:", i);
+            for (j = 0; j < n_ports; j++) {
+                printf(" %"PRIu16, ports[j]);
+            }
+            printf("\n");
+        }
+    }
+    dpif_close(&dpif);
+}
 \f
 /* Generic commands. */
 
@@ -1526,6 +1602,8 @@ static struct command all_commands[] = {
     { "get-idx", 1, 1, do_get_idx },
     { "get-name", 1, 1, do_get_name },
     { "showdp", 0, INT_MAX, do_show_dp },
+    { "dp-dump-flows", 1, 1, do_dp_dump_flows },
+    { "dp-dump-groups", 1, 1, do_dp_dump_groups },
 #endif
 
     { "show", 1, 1, do_show },