This will be useful for debugging CFM problems in the future.
#include <stdlib.h>
#include <string.h>
+#include "dynamic-string.h"
#include "flow.h"
#include "hash.h"
#include "hmap.h"
}
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);
}
}
}
}
+
+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);
+ }
+}
struct flow;
struct ofpbuf;
+struct ds;
/* Ethernet destination address of CCM packets. */
static const uint8_t eth_addr_ccm[6] OVS_UNUSED
void cfm_process_heartbeat(struct cfm *, const struct ofpbuf *packet);
+void cfm_dump_ds(const struct cfm *, struct ds *);
+
#endif /* cfm.h */
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);
/* 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);
ds_destroy(&ds);
}
\f
+/* 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);
+}
+\f
/* QoS unixctl user interface functions. */
struct qos_unixctl_show_cbdata {
.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"