cfm: No longer keep track of bad CCMs.
authorEthan Jackson <ethan@nicira.com>
Thu, 12 May 2011 00:50:16 +0000 (17:50 -0700)
committerEthan Jackson <ethan@nicira.com>
Fri, 13 May 2011 20:09:27 +0000 (13:09 -0700)
According to the 802.1ag specification, reception of a CCM from an
unexpected source should trigger a fault. This patch causes the CFM
module to simply warn instead.  There are several reasons for this
change outlined below.

  - Faults can cause controllers to make potentially expensive
    changes to the network topology.
  - Faults can be maliciously triggered by crafting invalid CCMs.
  - With this patch, cfm->fault and rmp->fault are only updated in
    cfm_run() making the code easier to debug and reason about.

lib/cfm.c

index 943cfc10ddc54a09b4cd56abfa9d260e35adb9d3..076344c264bcc2db23ea2827669504afa2ae092f 100644 (file)
--- a/lib/cfm.c
+++ b/lib/cfm.c
@@ -45,8 +45,6 @@ struct cfm_internal {
 
     struct timer tx_timer;    /* Send CCM when expired. */
     struct timer fault_timer; /* Check for faults when expired. */
-
-    long long x_recv_time;
 };
 
 static int
@@ -139,7 +137,6 @@ cfm_create(void)
 
     cfmi = xzalloc(sizeof *cfmi);
     cfm  = &cfmi->cfm;
-    cfmi->x_recv_time = LLONG_MIN;
 
     hmap_init(&cfm->remote_mps);
     return cfm;
@@ -168,17 +165,13 @@ cfm_destroy(struct cfm *cfm)
 void
 cfm_run(struct cfm *cfm)
 {
-    long long now = time_msec();
     struct cfm_internal *cfmi = cfm_to_internal(cfm);
 
     if (timer_expired(&cfmi->fault_timer)) {
-        bool fault;
+        long long int interval = cfm_fault_interval(cfmi);
         struct remote_mp *rmp;
-        long long int interval;
-
-        interval = cfm_fault_interval(cfmi);
-        fault = now < cfmi->x_recv_time + interval;
 
+        cfm->fault = false;
         HMAP_FOR_EACH (rmp, node, &cfm->remote_mps) {
             if (rmp->recv_time < timer_enabled_at(&cfmi->fault_timer, interval)
                 || timer_expired_at(&cfmi->fault_timer, rmp->recv_time)) {
@@ -186,11 +179,10 @@ cfm_run(struct cfm *cfm)
             }
 
             if (rmp->fault) {
-                fault = true;
+                cfm->fault = true;
             }
         }
 
-        cfm->fault = fault;
         timer_set_duration(&cfmi->fault_timer, interval);
     }
 }
@@ -379,8 +371,8 @@ cfm_process_heartbeat(struct cfm *cfm, const struct ofpbuf *p)
     }
 
     /* According to the 802.1ag specification, reception of a CCM with an
-     * incorrect ccm_interval should trigger a fault.  We ignore this
-     * requirement for several reasons.
+     * incorrect ccm_interval, unexpected MAID, or unexpected MPID should
+     * trigger a fault.  We ignore this requirement for several reasons.
      *
      * Faults can cause a controller or Open vSwitch to make potentially
      * expensive changes to the network topology.  It seems prudent to trigger
@@ -388,8 +380,6 @@ cfm_process_heartbeat(struct cfm *cfm, const struct ofpbuf *p)
      * bonds. Furthermore, faults can be maliciously triggered by crafting
      * invalid CCMs. */
     if (memcmp(ccm->maid, cfm->maid, sizeof ccm->maid)) {
-        cfmi->x_recv_time = time_msec();
-        cfm->fault = true;
         VLOG_WARN_RL(&rl, "Received unexpected remote MAID from MAC "
                      ETH_ADDR_FMT, ETH_ADDR_ARGS(eth->eth_src));
     } else {
@@ -407,8 +397,6 @@ cfm_process_heartbeat(struct cfm *cfm, const struct ofpbuf *p)
                              rmp->mpid);
             }
         } else {
-            cfmi->x_recv_time = time_msec();
-            cfm->fault = true;
             VLOG_WARN_RL(&rl, "Received unexpected remote MPID %d from MAC "
                          ETH_ADDR_FMT, ccm_mpid, ETH_ADDR_ARGS(eth->eth_src));
         }
@@ -419,7 +407,6 @@ 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,
@@ -431,11 +418,6 @@ cfm_dump_ds(const struct cfm *cfm, struct ds *ds)
     ds_put_format(ds, "\tnext fault check: %lldms\n",
                   timer_msecs_until_expired(&cfmi->fault_timer));
 
-    if (cfmi->x_recv_time != LLONG_MIN) {
-        ds_put_format(ds, "\ttime since bad CCM rx: %lldms\n",
-                      now - cfmi->x_recv_time);
-    }
-
     ds_put_cstr(ds, "\n");
     HMAP_FOR_EACH (rmp, node, &cfm->remote_mps) {
         ds_put_format(ds, "Remote MPID %"PRIu16": %s\n", rmp->mpid,