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

Alex Wang alexw at nicira.com
Tue Apr 29 23:15:39 UTC 2014


This commit adds a new requirement that cfm session must receive
at least one ccm every 100 * cfm_interval amount of time in demand
mode.  Otherwise, even if the data packets are received on the
monitored interface, the cfm session still reports "[recv]" fault.

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 commit can
prevent the remote CFM session from falsely declaring tunnel liveness
in this situation.

Signed-off-by: Alex Wang <alexw at nicira.com>

---
PATCH -> V2:
- hard code the demand_rx_ccm interval to be 100 * cfm_interval.
---
 lib/cfm.c            |   12 +++++++-
 tests/cfm.at         |   75 ++++++++++++++++++++++++++++++++++++++++++++++++++
 vswitchd/vswitch.xml |    7 +++--
 3 files changed, 90 insertions(+), 4 deletions(-)

diff --git a/lib/cfm.c b/lib/cfm.c
index 6a173a7..1b32625 100644
--- a/lib/cfm.c
+++ b/lib/cfm.c
@@ -137,6 +137,11 @@ struct cfm {
     /* True when the variables returned by cfm_get_*() are changed
      * since last check. */
     bool status_changed;
+
+    /* When 'cfm->demand' is set, at least one ccm is required to be received
+     * every 100 * cfm_interval.  If ccm is not received within this interval,
+     * even if data packets are received, the cfm fault will be set. */
+    struct timer demand_rx_ccm_t;
 };
 
 /* Remote MPs represent foreign network entities that are configured to have
@@ -459,7 +464,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;
         }
 
@@ -836,6 +842,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) {
+                    timer_set_duration(&cfm->demand_rx_ccm_t,
+                                       100 * cfm->ccm_interval_ms);
+                }
             }
             rmp->recv = true;
             cfm->recv_fault |= cfm_fault;
diff --git a/tests/cfm.at b/tests/cfm.at
index a3c44a1..fdca4ac 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,68 @@ 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])
+
+# wait longer, since the demand_rx_ccm interval is 100 * 300 ms.
+# 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 400`
+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/vswitch.xml b/vswitchd/vswitch.xml
index 78594e7..91dfdf9 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -2231,9 +2231,10 @@
           <ref column="other_config" key="cfm_extended"/> is true, the CFM
           module operates in demand mode.  When in demand mode, traffic
           received on the <ref table="Interface"/> is used to indicate
-          liveness.  CCMs are still transmitted and received, but if the
-          <ref table="Interface"/> is receiving traffic, their absence does not
-          cause a connectivity fault.
+          liveness.  CCMs are still transmitted and received.  At least one
+          CCM must be received every 100 * <ref column="other_config"
+          key="cfm_interval"/> amount of time.  Otherwise, even if traffic
+          are received, the CFM module will raise the connectivity fault.
         </p>
 
         <p>
-- 
1.7.9.5




More information about the dev mailing list