This will be useful for debugging CFM problems in the future.
---
 lib/cfm.c                  |   40 +++++++++++++++++++++++++++++++++++++++-
 lib/cfm.h                  |    3 +++
 vswitchd/bridge.c          |   29 +++++++++++++++++++++++++++++
 vswitchd/ovs-vswitchd.8.in |    3 +++
 4 files changed, 74 insertions(+), 1 deletions(-)

diff --git a/lib/cfm.c b/lib/cfm.c
index f017e73..b6cc115 100644
--- a/lib/cfm.c
+++ b/lib/cfm.c
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "dynamic-string.h"
 #include "flow.h"
 #include "hash.h"
 #include "hmap.h"
@@ -81,7 +82,7 @@ ms_to_ccm_interval(int interval_ms)
 }
 
 static struct cfm_internal *
-cfm_to_internal(struct cfm *cfm)
+cfm_to_internal(const struct cfm *cfm)
 {
     return CONTAINER_OF(cfm, struct cfm_internal, cfm);
 }
@@ -449,3 +450,40 @@ cfm_process_heartbeat(struct cfm *cfm, const struct ofpbuf 
*p)
         }
     }
 }
+
+static void
+put_remote_mp(struct ds *ds, const char *header,
+              const struct remote_mp *rmp)
+{
+    ds_put_format(ds, "%s %"PRIu16": %s\n", header, rmp->mpid,
+                  rmp->fault ? "fault" : "");
+    ds_put_format(ds, "\ttime since CCM rx: %lldms\n",
+                  time_msec() - rmp->recv_time);
+}
+
+void
+cfm_dump_ds(const struct cfm *cfm, struct ds *ds)
+{
+    const struct cfm_internal *cfmi = cfm_to_internal(cfm);
+    long long int now = time_msec();
+    struct remote_mp *rmp;
+
+    ds_put_format(ds, "MPID %"PRIu16": %s\n", cfm->mpid,
+                  cfm->fault ? "fault" : "");
+
+    ds_put_format(ds, "\tinterval: %dms\n", cfmi->ccm_interval_ms);
+    ds_put_format(ds, "\ttime since CCM tx: %lldms\n", now - cfmi->ccm_sent);
+    ds_put_format(ds, "\ttime since fault check: %lldms\n",
+                  now - cfmi->fault_check);
+    ds_put_format(ds, "\tunexpected remote MAIDS: %s\n",
+                  !hmap_is_empty(&cfmi->x_remote_maids) ? "true" : "false");
+
+    ds_put_cstr(ds, "\n");
+    HMAP_FOR_EACH (rmp, node, &cfm->remote_mps) {
+        put_remote_mp(ds, "Remote MPID", rmp);
+    }
+
+    HMAP_FOR_EACH (rmp, node, &cfmi->x_remote_mps) {
+        put_remote_mp(ds, "Unexpected Remote MPID", rmp);
+    }
+}
diff --git a/lib/cfm.h b/lib/cfm.h
index e4bb6df..e8dd3a6 100644
--- a/lib/cfm.h
+++ b/lib/cfm.h
@@ -24,6 +24,7 @@
 
 struct flow;
 struct ofpbuf;
+struct ds;
 
 /* Ethernet destination address of CCM packets. */
 static const uint8_t eth_addr_ccm[6] OVS_UNUSED
@@ -106,4 +107,6 @@ bool cfm_should_process_flow(const struct flow *);
 
 void cfm_process_heartbeat(struct cfm *, const struct ofpbuf *packet);
 
+void cfm_dump_ds(const struct cfm *, struct ds *);
+
 #endif /* cfm.h */
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 0ed0fea..44e4766 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -267,6 +267,7 @@ static uint64_t bridge_pick_datapath_id(struct bridge *,
 static uint64_t dpid_from_hash(const void *, size_t nbytes);
 
 static unixctl_cb_func bridge_unixctl_fdb_show;
+static unixctl_cb_func cfm_unixctl_show;
 static unixctl_cb_func qos_unixctl_show;
 
 static void bond_init(void);
@@ -345,6 +346,7 @@ bridge_init(const char *remote)
 
     /* Register unixctl commands. */
     unixctl_command_register("fdb/show", bridge_unixctl_fdb_show, NULL);
+    unixctl_command_register("cfm/show", cfm_unixctl_show, NULL);
     unixctl_command_register("qos/show", qos_unixctl_show, NULL);
     unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows,
                              NULL);
@@ -1515,6 +1517,33 @@ bridge_unixctl_fdb_show(struct unixctl_conn *conn,
     ds_destroy(&ds);
 }
 
+/* CFM unixctl user interface functions. */
+static void
+cfm_unixctl_show(struct unixctl_conn *conn,
+                 const char *args, void *aux OVS_UNUSED)
+{
+    struct ds ds = DS_EMPTY_INITIALIZER;
+    struct iface *iface;
+    const struct cfm *cfm;
+
+    iface = iface_find(args);
+    if (!iface) {
+        unixctl_command_reply(conn, 501, "no such interface");
+        return;
+    }
+
+    cfm = ofproto_iface_get_cfm(iface->port->bridge->ofproto, iface->dp_ifidx);
+
+    if (!cfm) {
+        unixctl_command_reply(conn, 501, "CFM not enabled");
+        return;
+    }
+
+    cfm_dump_ds(cfm, &ds);
+    unixctl_command_reply(conn, 200, ds_cstr(&ds));
+    ds_destroy(&ds);
+}
+
 /* QoS unixctl user interface functions. */
 
 struct qos_unixctl_show_cbdata {
diff --git a/vswitchd/ovs-vswitchd.8.in b/vswitchd/ovs-vswitchd.8.in
index f62f93f..4c02f8a 100644
--- a/vswitchd/ovs-vswitchd.8.in
+++ b/vswitchd/ovs-vswitchd.8.in
@@ -116,6 +116,9 @@ Causes \fBovs\-vswitchd\fR to gracefully terminate.
 .IP "\fBqos/show\fR \fIinterface\fR"
 Queries the kernel for Quality of Service configuration and statistics
 associated with the given \fIinterface\fR.
+.IP "\fBcfm/show\fR \fIinterface\fR"
+Displays detailed information about Connectivity Fault Management
+configured on \fIinterface\fR.
 .SS "BRIDGE COMMANDS"
 These commands manage bridges.
 .IP "\fBfdb/show\fR \fIbridge\fR"
-- 
1.7.4.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to