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 <al...@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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev