From 5767a79a40599e5e6e70662833b27ffdbdab7e37 Mon Sep 17 00:00:00 2001 From: Alex Wang Date: Wed, 9 Apr 2014 10:58:54 -0700 Subject: [PATCH] cfm: Require ccm received in demand mode. 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 Acked-by: Ethan Jackson --- 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 6a173a709..1b3262529 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 a3c44a158..fdca4ace5 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 5aec270ad..aa9168d17 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -2231,9 +2231,10 @@ is true, the CFM module operates in demand mode. When in demand mode, traffic received on the is used to indicate - liveness. CCMs are still transmitted and received, but if the - 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 * amount of time. Otherwise, even if traffic + are received, the CFM module will raise the connectivity fault.

-- 2.43.0