cfm: Allow manual override of CFM fault status.
authorEthan Jackson <ethan@nicira.com>
Fri, 27 Jan 2012 02:58:51 +0000 (18:58 -0800)
committerEthan Jackson <ethan@nicira.com>
Fri, 3 Feb 2012 00:56:09 +0000 (16:56 -0800)
This can be useful when testing.

Suggested-by: Reid Price <reid@nicira.com>
Signed-off-by: Ethan Jackson <ethan@nicira.com>
lib/cfm.c
vswitchd/ovs-vswitchd.8.in

index 1e05853..d62d4e2 100644 (file)
--- a/lib/cfm.c
+++ b/lib/cfm.c
@@ -90,6 +90,9 @@ struct cfm {
     bool opup;             /* Operational State. */
     bool remote_opup;      /* Remote Operational State. */
 
     bool opup;             /* Operational State. */
     bool remote_opup;      /* Remote Operational State. */
 
+    int fault_override;    /* Manual override of 'fault' status.
+                              Ignored if negative. */
+
     uint32_t seq;          /* The sequence number of our last CCM. */
     uint8_t ccm_interval;  /* The CCM transmission interval. */
     int ccm_interval_ms;   /* 'ccm_interval' in milliseconds. */
     uint32_t seq;          /* The sequence number of our last CCM. */
     uint8_t ccm_interval;  /* The CCM transmission interval. */
     int ccm_interval_ms;   /* 'ccm_interval' in milliseconds. */
@@ -124,6 +127,7 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(20, 30);
 static struct hmap all_cfms = HMAP_INITIALIZER(&all_cfms);
 
 static unixctl_cb_func cfm_unixctl_show;
 static struct hmap all_cfms = HMAP_INITIALIZER(&all_cfms);
 
 static unixctl_cb_func cfm_unixctl_show;
+static unixctl_cb_func cfm_unixctl_set_fault;
 
 static const uint8_t *
 cfm_ccm_addr(const struct cfm *cfm)
 
 static const uint8_t *
 cfm_ccm_addr(const struct cfm *cfm)
@@ -235,6 +239,8 @@ cfm_init(void)
 {
     unixctl_command_register("cfm/show", "[interface]", 0, 1, cfm_unixctl_show,
                              NULL);
 {
     unixctl_command_register("cfm/show", "[interface]", 0, 1, cfm_unixctl_show,
                              NULL);
+    unixctl_command_register("cfm/set-fault", "[interface] normal|false|true",
+                             1, 2, cfm_unixctl_set_fault, NULL);
 }
 
 /* Allocates a 'cfm' object called 'name'.  'cfm' should be initialized by
 }
 
 /* Allocates a 'cfm' object called 'name'.  'cfm' should be initialized by
@@ -250,6 +256,7 @@ cfm_create(const char *name)
     cfm_generate_maid(cfm);
     hmap_insert(&all_cfms, &cfm->hmap_node, hash_string(cfm->name, 0));
     cfm->remote_opup = true;
     cfm_generate_maid(cfm);
     hmap_insert(&all_cfms, &cfm->hmap_node, hash_string(cfm->name, 0));
     cfm->remote_opup = true;
+    cfm->fault_override = -1;
     return cfm;
 }
 
     return cfm;
 }
 
@@ -546,6 +553,9 @@ cfm_process_heartbeat(struct cfm *cfm, const struct ofpbuf *p)
 bool
 cfm_get_fault(const struct cfm *cfm)
 {
 bool
 cfm_get_fault(const struct cfm *cfm)
 {
+    if (cfm->fault_override >= 0) {
+        return cfm->fault_override;
+    }
     return cfm->fault;
 }
 
     return cfm->fault;
 }
 
@@ -589,9 +599,10 @@ cfm_print_details(struct ds *ds, const struct cfm *cfm)
     struct remote_mp *rmp;
 
     ds_put_format(ds, "---- %s ----\n", cfm->name);
     struct remote_mp *rmp;
 
     ds_put_format(ds, "---- %s ----\n", cfm->name);
-    ds_put_format(ds, "MPID %"PRIu64":%s%s%s\n", cfm->mpid,
+    ds_put_format(ds, "MPID %"PRIu64":%s%s%s%s\n", cfm->mpid,
                   cfm->extended ? " extended" : "",
                   cfm->extended ? " extended" : "",
-                  cfm->fault ? " fault" : "",
+                  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");
                   cfm->unexpected_recv ? " unexpected_recv" : "");
 
     ds_put_format(ds, "\topstate: %s\n", cfm->opup ? "up" : "down");
@@ -636,3 +647,38 @@ cfm_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[],
     unixctl_command_reply(conn, 200, ds_cstr(&ds));
     ds_destroy(&ds);
 }
     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");
+}
index 01dfcdf..1abae6f 100644 (file)
@@ -118,6 +118,10 @@ Displays detailed information about Connectivity Fault Management
 configured on \fIinterface\fR.  If \fIinterface\fR is not specified,
 then displays detailed information about all interfaces with CFM
 enabled.
 configured on \fIinterface\fR.  If \fIinterface\fR is not specified,
 then displays detailed information about all interfaces with CFM
 enabled.
+.IP "\fBcfm/set-fault\fR [\fIinterface\fR] \fIstatus\fR"
+Force the fault status of the CFM module on \fIinterface\fR (or all
+interfaces if none is given) to be \fIstatus\fR.  \fIstatus\fR can be
+"true", "false", or "normal" which reverts to the standard behavior.
 .IP "\fBstp/tcn\fR [\fIbridge\fR]"
 Forces a topology change event on \fIbridge\fR if it's running STP.  This
 may cause it to send Topology Change Notifications to its peers and flush
 .IP "\fBstp/tcn\fR [\fIbridge\fR]"
 Forces a topology change event on \fIbridge\fR if it's running STP.  This
 may cause it to send Topology Change Notifications to its peers and flush