[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