#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.
return len;
}
-static void
+void
ofp_print_actions(struct ds *string, const struct ofp_action_header *action,
size_t actions_len)
{
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);
struct ofp_flow_mod;
struct ofp_match;
+struct ds;
+struct ofp_action_header;
#ifdef __cplusplus
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
#include "coverage.h"
#include "discovery.h"
#include "dpif.h"
+#include "dynamic-string.h"
#include "executer.h"
#include "fail-open.h"
#include "in-band.h"
#include "svec.h"
#include "tag.h"
#include "timeval.h"
+#include "unixctl.h"
#include "vconn.h"
#include "vconn-ssl.h"
#include "xtoxll.h"
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;
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 *,
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 *);
}
}
+ unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows);
+
bridge_reconfigure();
}
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)
{