+ return NULL;
+}
+
+static void
+cfm_print_details(struct ds *ds, const struct cfm *cfm)
+{
+ struct remote_mp *rmp;
+
+ ds_put_format(ds, "---- %s ----\n", cfm->name);
+ ds_put_format(ds, "MPID %"PRIu64":%s%s%s%s\n", cfm->mpid,
+ cfm->extended ? " extended" : "",
+ cfm_get_fault(cfm) ? " fault" : "",
+ cfm->fault_override >= 0 ? " fault_override" : "",
+ cfm->unexpected_recv ? " unexpected_recv" : "");
+
+ ds_put_format(ds, "\topstate: %s\n", cfm->opup ? "up" : "down");
+ ds_put_format(ds, "\tremote_opstate: %s\n",
+ cfm->remote_opup ? "up" : "down");
+ ds_put_format(ds, "\tinterval: %dms\n", cfm->ccm_interval_ms);
+ ds_put_format(ds, "\tnext CCM tx: %lldms\n",
+ timer_msecs_until_expired(&cfm->tx_timer));
+ ds_put_format(ds, "\tnext fault check: %lldms\n",
+ timer_msecs_until_expired(&cfm->fault_timer));
+
+ HMAP_FOR_EACH (rmp, node, &cfm->remote_mps) {
+ ds_put_format(ds, "Remote MPID %"PRIu64":%s\n",
+ rmp->mpid,
+ rmp->rdi ? " rdi" : "");
+ ds_put_format(ds, "\trecv since check: %s\n",
+ rmp->recv ? "true" : "false");
+ ds_put_format(ds, "\topstate: %s\n", rmp->opup? "up" : "down");
+ }
+}
+
+static void
+cfm_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[],
+ void *aux OVS_UNUSED)
+{
+ struct ds ds = DS_EMPTY_INITIALIZER;
+ const struct cfm *cfm;
+
+ if (argc > 1) {
+ cfm = cfm_find(argv[1]);
+ if (!cfm) {
+ unixctl_command_reply(conn, 501, "no such CFM object");
+ return;
+ }
+ cfm_print_details(&ds, cfm);
+ } else {
+ HMAP_FOR_EACH (cfm, hmap_node, &all_cfms) {
+ cfm_print_details(&ds, cfm);
+ }
+ }
+
+ unixctl_command_reply(conn, 200, ds_cstr(&ds));
+ ds_destroy(&ds);
+}
+
+static void
+cfm_unixctl_set_fault(struct unixctl_conn *conn, int argc, const char *argv[],
+ void *aux OVS_UNUSED)
+{
+ const char *fault_str = argv[argc - 1];
+ int fault_override;
+ struct cfm *cfm;
+
+ if (!strcasecmp("true", fault_str)) {
+ fault_override = 1;
+ } else if (!strcasecmp("false", fault_str)) {
+ fault_override = 0;
+ } else if (!strcasecmp("normal", fault_str)) {
+ fault_override = -1;
+ } else {
+ unixctl_command_reply(conn, 501, "unknown fault string");
+ return;
+ }
+
+ if (argc > 2) {
+ cfm = cfm_find(argv[1]);
+ if (!cfm) {
+ unixctl_command_reply(conn, 501, "no such CFM object");
+ return;
+ }
+ cfm->fault_override = fault_override;
+ } else {
+ HMAP_FOR_EACH (cfm, hmap_node, &all_cfms) {
+ cfm->fault_override = fault_override;
+ }
+ }
+
+ unixctl_command_reply(conn, 200, "OK");