[ovs-dev] [PATCH 1/2] cfm: Require ccm received in demand mode.

Alex Wang alexw at nicira.com
Mon Apr 28 06:03:53 UTC 2014


This commit adds a new cfm configuration option "demand_rx_ccm" which
represents a time interval in milliseconds.  It is only effective when
cfm session is in demand mode.  It requires cfm session receive at
least one ccm during the "demand_rx_ccm" interval.  Otherwise, the
cfm session will report "[recv]" fault.

Signed-off-by: Alex Wang <alexw at nicira.com>
---
 lib/cfm.c            |   24 +++++++++++++-
 lib/cfm.h            |    1 +
 tests/cfm.at         |   87 ++++++++++++++++++++++++++++++++++++++++++++++++++
 vswitchd/bridge.c    |    2 ++
 vswitchd/vswitch.xml |   24 ++++++++++++++
 5 files changed, 137 insertions(+), 1 deletion(-)

diff --git a/lib/cfm.c b/lib/cfm.c
index 6a173a7..c282838 100644
--- a/lib/cfm.c
+++ b/lib/cfm.c
@@ -137,6 +137,13 @@ struct cfm {
     /* True when the variables returned by cfm_get_*() are changed
      * since last check. */
     bool status_changed;
+
+    /* When 'cfm->demand' is set, users can specify the 'demand_rx_ccm'.
+     * interval.  If ccm is not received within this interval, even if
+     * data packets are received, the cfm fault will be set.  The configured
+     * value should be at least 20 * cfm_interval. */
+    int demand_rx_ccm;
+    struct timer demand_rx_ccm_t;
 };
 
 /* Remote MPs represent foreign network entities that are configured to have
@@ -459,7 +466,8 @@ cfm_run(struct cfm *cfm) OVS_EXCLUDED(mutex)
         if (cfm->demand) {
             uint64_t rx_packets = cfm_rx_packets(cfm);
             demand_override = hmap_count(&cfm->remote_mps) == 1
-                && rx_packets > cfm->rx_packets;
+                && rx_packets > cfm->rx_packets
+                && !timer_expired(&cfm->demand_rx_ccm_t);
             cfm->rx_packets = rx_packets;
         }
 
@@ -675,6 +683,16 @@ cfm_configure(struct cfm *cfm, const struct cfm_settings *s)
         cfm->demand = false;
     }
 
+    if (cfm->demand) {
+        cfm->demand_rx_ccm = s->demand_rx_ccm ?
+            MAX(s->demand_rx_ccm, 20 * interval_ms) : 0;
+        if (cfm->demand_rx_ccm) {
+            timer_set_duration(&cfm->demand_rx_ccm_t, cfm->demand_rx_ccm);
+        } else {
+            timer_set_infinite(&cfm->demand_rx_ccm_t);
+        }
+    }
+
     if (interval != cfm->ccm_interval || interval_ms != cfm->ccm_interval_ms) {
         cfm->ccm_interval = interval;
         cfm->ccm_interval_ms = interval_ms;
@@ -836,6 +854,10 @@ cfm_process_heartbeat(struct cfm *cfm, const struct ofpbuf *p)
             rmp->mpid = ccm_mpid;
             if (!cfm_fault) {
                 rmp->num_health_ccm++;
+                if (cfm->demand && cfm->demand_rx_ccm) {
+                    timer_set_duration(&cfm->demand_rx_ccm_t,
+                                       cfm->demand_rx_ccm);
+                }
             }
             rmp->recv = true;
             cfm->recv_fault |= cfm_fault;
diff --git a/lib/cfm.h b/lib/cfm.h
index 13fdc60..e21ed1f 100644
--- a/lib/cfm.h
+++ b/lib/cfm.h
@@ -52,6 +52,7 @@ enum cfm_fault_reason {
 
 struct cfm_settings {
     uint64_t mpid;              /* The MPID of this CFM. */
+    uint64_t demand_rx_ccm;     /* Require recv ccm when in demand mode. */
     int interval;               /* The requested transmission interval. */
     bool extended;              /* Run in extended mode. */
     bool demand;                /* Run in demand mode. */
diff --git a/tests/cfm.at b/tests/cfm.at
index a3c44a1..e1d112a 100644
--- a/tests/cfm.at
+++ b/tests/cfm.at
@@ -14,6 +14,19 @@ Remote MPID $7
 ])
 ])
 
+m4_define([CFM_CHECK_EXTENDED_FAULT], [
+AT_CHECK([ovs-appctl cfm/show $1 | sed -e '/next CCM tx:/d' | sed -e '/next fault check:/d' | sed -e  '/recv since check:/d'],[0],
+[dnl
+---- $1 ----
+MPID $2: extended
+	fault: $3
+	average health: $4
+	opstate: $5
+	remote_opstate: $6
+	interval: $7
+])
+])
+
 m4_define([CFM_VSCTL_LIST_IFACE], [
 AT_CHECK([ovs-vsctl list interface $1 | sed -n '/$2/p'],[0],
 [dnl
@@ -101,6 +114,80 @@ done
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+# test demand_rx_ccm under demand mode.
+AT_SETUP([cfm - demand_rx_ccm])
+#Create 2 bridges connected by patch ports and enable cfm
+OVS_VSWITCHD_START([add-br br1 -- \
+                    set bridge br1 datapath-type=dummy \
+                    other-config:hwaddr=aa:55:aa:56:00:00 -- \
+                    add-port br1 p1 -- set Interface p1 type=patch \
+                    options:peer=p0 ofport_request=2 -- \
+                    add-port br0 p0 -- set Interface p0 type=patch \
+                    options:peer=p1 ofport_request=1 -- \
+                    set Interface p0 cfm_mpid=1 other_config:cfm_interval=300 other_config:cfm_extended=true other_config:cfm_demand=true -- \
+                    set Interface p1 cfm_mpid=2 other_config:cfm_interval=300 other_config:cfm_extended=true other_config:cfm_demand=true])
+
+ovs-appctl time/stop
+# wait for a while to stablize cfm. (need a longer time, since in demand mode
+# the fault interval is (MAX(ccm_interval_ms, 500) * 3.5) ms)
+for i in `seq 0 200`; do ovs-appctl time/warp 100; done
+CFM_CHECK_EXTENDED([p0], [1], [100], [up], [up], [300ms], [2], [up])
+CFM_CHECK_EXTENDED([p1], [2], [100], [up], [up], [300ms], [1], [up])
+
+# turn off the cfm on p1.
+AT_CHECK([ovs-vsctl clear Interface p1 cfm_mpid])
+# cfm should never go down while receiving data packets.
+for i in `seq 0 200`
+do
+    ovs-appctl time/warp 100
+    AT_CHECK([ovs-ofctl packet-out br1 3 2  "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
+             [0], [stdout], [])
+done
+CFM_CHECK_EXTENDED([p0], [1], [0], [up], [up], [300ms], [2], [up])
+
+# configure the demand_rx_ccm.
+AT_CHECK([ovs-vsctl set Interface p0 other_config:demand_rx_ccm=5000])
+# since there is no ccm received, the [recv] fault should be raised.
+for i in `seq 0 200`
+do
+    ovs-appctl time/warp 100
+    AT_CHECK([ovs-ofctl packet-out br1 3 2  "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
+             [0], [stdout], [])
+done
+CFM_CHECK_EXTENDED_FAULT([p0], [1], [recv], [0], [up], [up], [300ms])
+
+# now turn on the cfm on p1 again,
+AT_CHECK([ovs-vsctl set Interface p1 cfm_mpid=2])
+# cfm should be up for both p0 and p1
+for i in `seq 0 200`; do ovs-appctl time/warp 100; done
+CFM_CHECK_EXTENDED([p0], [1], [100], [up], [up], [300ms], [2], [up])
+CFM_CHECK_EXTENDED([p1], [2], [100], [up], [up], [300ms], [1], [up])
+
+# now turn off the cfm on p1 again
+AT_CHECK([ovs-vsctl clear Interface p1 cfm_mpid])
+# since there is no ccm received, the [recv] fault should be raised.
+for i in `seq 0 200`
+do
+    ovs-appctl time/warp 100
+    AT_CHECK([ovs-ofctl packet-out br1 3 2  "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
+             [0], [stdout], [])
+done
+CFM_CHECK_EXTENDED_FAULT([p0], [1], [recv], [0], [up], [up], [300ms])
+
+# remove the demand_rx_ccm configuration.
+AT_CHECK([ovs-vsctl remove Interface p0 other_config demand_rx_ccm=5000])
+# now, the cfm should be up again.
+for i in `seq 0 200`
+do
+    ovs-appctl time/warp 100
+    AT_CHECK([ovs-ofctl packet-out br1 3 2  "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
+             [0], [stdout], [])
+done
+CFM_CHECK_EXTENDED_FAULT([p0], [1], [recv], [0], [up], [up], [300ms])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 # test cfm_flap_count.
 AT_SETUP([cfm - flap_count])
 #Create 2 bridges connected by patch ports and enable cfm
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 84e9ab8..479179b 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -3712,6 +3712,8 @@ iface_configure_cfm(struct iface *iface)
 
     s.mpid = *cfg->cfm_mpid;
     s.interval = smap_get_int(&iface->cfg->other_config, "cfm_interval", 0);
+    s.demand_rx_ccm = smap_get_int(&iface->cfg->other_config,
+                                   "demand_rx_ccm", 0);
     cfm_ccm_vlan = smap_get(&iface->cfg->other_config, "cfm_ccm_vlan");
     s.ccm_pcp = smap_get_int(&iface->cfg->other_config, "cfm_ccm_pcp", 0);
 
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index 78594e7..78ccd24 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -2262,6 +2262,30 @@
         </p>
       </column>
 
+      <column name="other_config" key="demand_rx_ccm"
+              type='{"type": "integer"}'>
+        <p>
+          A time interval in milliseconds.  When set, must be greater than
+          twenty time of <ref column="other_config" key="cfm_interval"/>.
+        </p>
+
+        <p>
+          When configured and <ref column="other_config" key="cfm_demand"/>
+          is true, the CFM session is required to receive at least one CCM
+          during this interval.  Otherwise, the
+          <ref column="cfm_fault_status" key="recv"/> will be raised even
+          though data packet is received from the monitored interface.
+        </p>
+
+        <p>
+          Since the datapath flow is not purged when the userspace Open Vswitch
+          crashes, data packet can still be forwarded through the tunnel and
+          fool the remote CFM session in demand mode.  Thus, this option can
+          prevent the remote CFM session from falsely declaring tunnel liveness
+          in this situation.
+        </p>
+      </column>
+
       <column name="other_config" key="cfm_opstate"
               type='{"type": "string", "enum": ["set", ["down", "up"]]}'>
         When <code>down</code>, the CFM module marks all CCMs it generates as
-- 
1.7.9.5




More information about the dev mailing list