+ return NULL;
+}
+
+static void
+cfm_print_details(struct ds *ds, struct cfm *cfm) OVS_REQUIRES(mutex)
+{
+ struct remote_mp *rmp;
+ bool extended;
+ int fault;
+
+ atomic_read(&cfm->extended, &extended);
+
+ ds_put_format(ds, "---- %s ----\n", cfm->name);
+ ds_put_format(ds, "MPID %"PRIu64":%s%s\n", cfm->mpid,
+ extended ? " extended" : "",
+ cfm->fault_override >= 0 ? " fault_override" : "");
+
+ fault = cfm_get_fault__(cfm);
+ if (fault) {
+ ds_put_cstr(ds, "\tfault: ");
+ ds_put_cfm_fault(ds, fault);
+ ds_put_cstr(ds, "\n");
+ }
+
+ if (cfm->health == -1) {
+ ds_put_format(ds, "\taverage health: undefined\n");
+ } else {
+ ds_put_format(ds, "\taverage health: %d\n", cfm->health);
+ }
+ 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"\n", rmp->mpid);
+ 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) OVS_EXCLUDED(mutex)
+{
+ struct ds ds = DS_EMPTY_INITIALIZER;
+ struct cfm *cfm;
+
+ ovs_mutex_lock(&mutex);
+ if (argc > 1) {
+ cfm = cfm_find(argv[1]);
+ if (!cfm) {
+ unixctl_command_reply_error(conn, "no such CFM object");
+ goto out;
+ }
+ cfm_print_details(&ds, cfm);
+ } else {
+ HMAP_FOR_EACH (cfm, hmap_node, all_cfms) {
+ cfm_print_details(&ds, cfm);
+ }
+ }
+
+ unixctl_command_reply(conn, ds_cstr(&ds));
+ ds_destroy(&ds);
+out:
+ ovs_mutex_unlock(&mutex);
+}
+
+static void
+cfm_unixctl_set_fault(struct unixctl_conn *conn, int argc, const char *argv[],
+ void *aux OVS_UNUSED) OVS_EXCLUDED(mutex)
+{
+ const char *fault_str = argv[argc - 1];
+ int fault_override;
+ struct cfm *cfm;
+
+ ovs_mutex_lock(&mutex);
+ 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_error(conn, "unknown fault string");
+ goto out;
+ }
+
+ if (argc > 2) {
+ cfm = cfm_find(argv[1]);
+ if (!cfm) {
+ unixctl_command_reply_error(conn, "no such CFM object");
+ goto out;
+ }
+ cfm->fault_override = fault_override;
+ cfm_status_changed(cfm);
+ } else {
+ HMAP_FOR_EACH (cfm, hmap_node, all_cfms) {
+ cfm->fault_override = fault_override;
+ cfm_status_changed(cfm);
+ }
+ }
+
+ unixctl_command_reply(conn, "OK");
+
+out:
+ ovs_mutex_unlock(&mutex);