vswitchd: Add unixctl command to dump all flows, including hidden ones
authorJustin Pettit <jpettit@nicira.com>
Tue, 14 Jul 2009 20:03:57 +0000 (13:03 -0700)
committerJustin Pettit <jpettit@nicira.com>
Thu, 30 Jul 2009 00:04:18 +0000 (17:04 -0700)
Previously, the only way to query the flow table was to run "ovs-ofctl
dump-flows".  This returned most flows, but not those marked hidden by
secchan.  Hidden flows are setup by mechanisms such as in-band control,
since they must not be modified by users of the controller.  However,
when debugging problems on the switch, it is often useful to see what
the flow table is actually doing.  The new "bridge/dump-flows" command
added to ovs-appctl shows all flows being used by the OpenFlow stack.

lib/ofp-print.c
lib/ofp-print.h
secchan/ofproto.c
secchan/ofproto.h
vswitchd/bridge.c

index 1e0f0aa..63b59dd 100644 (file)
@@ -37,8 +37,6 @@
 #include "util.h"
 
 static void ofp_print_port_name(struct ds *string, uint16_t port);
-static void ofp_print_match(struct ds *, const struct ofp_match *,
-                            int verbosity);
 
 /* Returns a string that represents the contents of the Ethernet frame in the
  * 'len' bytes starting at 'data' to 'stream' as output by tcpdump.
@@ -380,7 +378,7 @@ ofp_print_action(struct ds *string, const struct ofp_action_header *ah,
     return len;
 }
 
-static void 
+void 
 ofp_print_actions(struct ds *string, const struct ofp_action_header *action,
                   size_t actions_len) 
 {
@@ -627,7 +625,7 @@ print_ip_netmask(struct ds *string, const char *leader, uint32_t ip,
     ds_put_char(string, ',');
 }
 
-static void
+void
 ofp_print_match(struct ds *f, const struct ofp_match *om, int verbosity)
 {
     char *s = ofp_match_to_string(om, verbosity);
index 2c9548b..a362a65 100644 (file)
@@ -24,6 +24,8 @@
 
 struct ofp_flow_mod;
 struct ofp_match;
+struct ds;
+struct ofp_action_header;
 
 #ifdef  __cplusplus
 extern "C" {
@@ -32,11 +34,15 @@ extern "C" {
 void ofp_print(FILE *, const void *, size_t, int verbosity);
 void ofp_print_packet(FILE *stream, const void *data, size_t len, size_t total_len);
 
+void ofp_print_actions(struct ds *, const struct ofp_action_header *, size_t);
+void ofp_print_match(struct ds *, const struct ofp_match *, int verbosity);
+
 char *ofp_to_string(const void *, size_t, int verbosity);
 char *ofp_match_to_string(const struct ofp_match *, int verbosity);
 char *ofp_packet_to_string(const void *data, size_t len, size_t total_len);
 char *ofp_message_type_to_string(uint8_t type);
 
+
 #ifdef  __cplusplus
 }
 #endif
index 19baab9..9f3a849 100644 (file)
@@ -26,6 +26,7 @@
 #include "coverage.h"
 #include "discovery.h"
 #include "dpif.h"
+#include "dynamic-string.h"
 #include "executer.h"
 #include "fail-open.h"
 #include "in-band.h"
@@ -51,6 +52,7 @@
 #include "svec.h"
 #include "tag.h"
 #include "timeval.h"
+#include "unixctl.h"
 #include "vconn.h"
 #include "vconn-ssl.h"
 #include "xtoxll.h"
@@ -2471,6 +2473,59 @@ handle_flow_stats_request(struct ofproto *p, struct ofconn *ofconn,
     return 0;
 }
 
+struct flow_stats_ds_cbdata {
+    struct ofproto *ofproto;
+    struct ds *results;
+};
+
+static void
+flow_stats_ds_cb(struct cls_rule *rule_, void *cbdata_)
+{
+    struct rule *rule = rule_from_cls_rule(rule_);
+    struct flow_stats_ds_cbdata *cbdata = cbdata_;
+    struct ds *results = cbdata->results;
+    struct ofp_match match;
+    uint64_t packet_count, byte_count;
+    size_t act_len = sizeof *rule->actions * rule->n_actions;
+
+    /* Don't report on subrules. */
+    if (rule->super != NULL) {
+        return;
+    }
+
+    query_stats(cbdata->ofproto, rule, &packet_count, &byte_count);
+    flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &match);
+
+    ds_put_format(results, "duration=%llds, ",
+                  (time_msec() - rule->created) / 1000);
+    ds_put_format(results, "priority=%u", rule->cr.priority);
+    ds_put_format(results, "n_packets=%"PRIu64", ", packet_count);
+    ds_put_format(results, "n_bytes=%"PRIu64", ", byte_count);
+    ofp_print_match(results, &match, true);
+    ofp_print_actions(results, &rule->actions->header, act_len);
+    ds_put_cstr(results, "\n");
+}
+
+/* Adds a pretty-printed description of all flows to 'results', including 
+ * those marked hidden by secchan (e.g., by in-band control). */
+void
+ofproto_get_all_flows(struct ofproto *p, struct ds *results)
+{
+    struct ofp_match match;
+    struct cls_rule target;
+    struct flow_stats_ds_cbdata cbdata;
+
+    memset(&match, 0, sizeof match);
+    match.wildcards = htonl(OFPFW_ALL);
+
+    cbdata.ofproto = p;
+    cbdata.results = results;
+
+    cls_rule_from_match(&target, &match, 0);
+    classifier_for_each_match(&p->cls, &target, CLS_INC_ALL,
+                              flow_stats_ds_cb, &cbdata);
+}
+
 struct aggregate_stats_cbdata {
     struct ofproto *ofproto;
     uint16_t out_port;
index f4c1b40..398cac4 100644 (file)
@@ -80,6 +80,7 @@ bool ofproto_get_discovery(const struct ofproto *);
 const char *ofproto_get_controller(const struct ofproto *);
 void ofproto_get_listeners(const struct ofproto *, struct svec *);
 void ofproto_get_snoops(const struct ofproto *, struct svec *);
+void ofproto_get_all_flows(struct ofproto *p, struct ds *);
 
 /* Functions for use by ofproto implementation modules, not by clients. */
 int ofproto_send_packet(struct ofproto *, const flow_t *,
index b107320..057172e 100644 (file)
@@ -192,6 +192,7 @@ enum { DP_MAX = 256 };
 static struct bridge *bridge_create(const char *name);
 static void bridge_destroy(struct bridge *);
 static struct bridge *bridge_lookup(const char *name);
+static void bridge_unixctl_dump_flows(struct unixctl_conn *, const char *);
 static int bridge_run_one(struct bridge *);
 static void bridge_reconfigure_one(struct bridge *);
 static void bridge_reconfigure_controller(struct bridge *);
@@ -303,6 +304,8 @@ bridge_init(void)
         }
     }
 
+    unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows);
+
     bridge_reconfigure();
 }
 
@@ -958,6 +961,27 @@ bridge_get_datapathid(const char *name)
     return br ? ofproto_get_datapath_id(br->ofproto) : 0;
 }
 
+/* Handle requests for a listing of all flows known by the OpenFlow
+ * stack, including those normally hidden. */
+static void
+bridge_unixctl_dump_flows(struct unixctl_conn *conn, const char *args)
+{
+    struct bridge *br;
+    struct ds results;
+    
+    br = bridge_lookup(args);
+    if (!br) {
+        unixctl_command_reply(conn, 501, "Unknown bridge");
+        return;
+    }
+
+    ds_init(&results);
+    ofproto_get_all_flows(br->ofproto, &results);
+
+    unixctl_command_reply(conn, 200, ds_cstr(&results));
+    ds_destroy(&results);
+}
+
 static int
 bridge_run_one(struct bridge *br)
 {