Acked-by: Ethan Jackson <et...@nicira.com>

On Tue, Apr 29, 2014 at 4:15 PM, Alex Wang <al...@nicira.com> wrote:
> This commit adds a requirement that bfd session must receive at least
> one bfd control packet every 100 * bfd->cfg_min_rx amount of time in
> forwarding_if_rx mode.  Otherwise, even if the data packets are received
> on the monitored interface, the bfd->forwarding is still false.
>
> 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 BFD session in forwarding_if_rx mode.  Thus, this commit
> can prevent the remote BFD session from falsely declaring tunnel liveness
> in this situation.
>
> Signed-off-by: Alex Wang <al...@nicira.com>
> ---
> PATCH -> V2:
> - hard code the demand_rx_bfd interval to be 100 * cfm_interval.
> ---
>  lib/bfd.c            |   27 ++++++++++----
>  tests/bfd.at         |  101 
> ++++++++++++++++++++++++++++++++++++++------------
>  vswitchd/vswitch.xml |   11 ++++--
>  3 files changed, 105 insertions(+), 34 deletions(-)
>
> diff --git a/lib/bfd.c b/lib/bfd.c
> index e3e3ae5..2d53bd2 100644
> --- a/lib/bfd.c
> +++ b/lib/bfd.c
> @@ -203,6 +203,12 @@ struct bfd {
>      bool forwarding_if_rx;
>      long long int forwarding_if_rx_detect_time;
>
> +    /* When 'bfd->forwarding_if_rx' is set, at least one bfd control packet
> +     * is required to be received every 100 * bfd->cfg_min_rx.  If bfd
> +     * control packet is not received within this interval, even if data
> +     * packets are received, the bfd->forwarding will still be false. */
> +    long long int demand_rx_bfd_time;
> +
>      /* BFD decay related variables. */
>      bool in_decay;                /* True when bfd is in decay. */
>      int decay_min_rx;             /* min_rx is set to decay_min_rx when */
> @@ -841,6 +847,10 @@ bfd_process_packet(struct bfd *bfd, const struct flow 
> *flow,
>      }
>      /* XXX: RFC 5880 Section 6.8.6 Demand mode related calculations here. */
>
> +    if (bfd->forwarding_if_rx) {
> +        bfd->demand_rx_bfd_time = time_msec() + 100 * bfd->cfg_min_rx;
> +    }
> +
>  out:
>      bfd_forwarding__(bfd);
>      ovs_mutex_unlock(&mutex);
> @@ -876,19 +886,22 @@ bfd_set_netdev(struct bfd *bfd, const struct netdev 
> *netdev)
>  static bool
>  bfd_forwarding__(struct bfd *bfd) OVS_REQUIRES(mutex)
>  {
> -    long long int time;
> +    long long int now = time_msec();
> +    bool forwarding_if_rx;
>      bool last_forwarding = bfd->last_forwarding;
>
>      if (bfd->forwarding_override != -1) {
>          return bfd->forwarding_override == 1;
>      }
>
> -    time = bfd->forwarding_if_rx_detect_time;
> -    bfd->last_forwarding = (bfd->state == STATE_UP
> -                            || (bfd->forwarding_if_rx && time > time_msec()))
> -                            && bfd->rmt_diag != DIAG_PATH_DOWN
> -                            && bfd->rmt_diag != DIAG_CPATH_DOWN
> -                            && bfd->rmt_diag != DIAG_RCPATH_DOWN;
> +    forwarding_if_rx = bfd->forwarding_if_rx
> +                       && bfd->forwarding_if_rx_detect_time > now
> +                       && bfd->demand_rx_bfd_time > now;
> +
> +    bfd->last_forwarding = (bfd->state == STATE_UP || forwarding_if_rx)
> +                           && bfd->rmt_diag != DIAG_PATH_DOWN
> +                           && bfd->rmt_diag != DIAG_CPATH_DOWN
> +                           && bfd->rmt_diag != DIAG_RCPATH_DOWN;
>      if (bfd->last_forwarding != last_forwarding) {
>          bfd->flap_count++;
>          bfd_status_changed(bfd);
> diff --git a/tests/bfd.at b/tests/bfd.at
> index 3723d60..f6f5592 100644
> --- a/tests/bfd.at
> +++ b/tests/bfd.at
> @@ -401,10 +401,9 @@ AT_CLEANUP
>
>  # forwarding_if_rx Test1
>  # Test1 tests the case when bfd is only enabled on one end of the link.
> -# Under this situation, the bfd state should be DOWN and the forwarding
> -# flag should be FALSE by default.  However, if forwarding_if_rx is
> -# enabled, as long as there is packet received, the bfd forwarding flag
> -# should be TRUE.
> +# Under this situation, the forwarding flag should always be false, even
> +# though there is data packet received, since there is no bfd control
> +# packet received during the demand_rx_bfd interval.
>  AT_SETUP([bfd - bfd forwarding_if_rx - bfd on one side])
>  OVS_VSWITCHD_START([add-br br1 -- set bridge br1 datapath-type=dummy -- \
>                      add-port br1 p1 -- set Interface p1 type=patch \
> @@ -438,15 +437,8 @@ do
>      AT_CHECK([ovs-ofctl packet-out br1 3 2  
> "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
>               [0], [stdout], [])
>  done
> -# the forwarding flag should be true, since there is data received.
> -BFD_CHECK([p0], [true], [false], [none], [down], [No Diagnostic], [none], 
> [down], [No Diagnostic])
> -
> -# reset bfd forwarding_if_rx.
> -AT_CHECK([ovs-vsctl set Interface p0 bfd:forwarding_if_rx=false], [0])
> -# forwarding flag should turn to false since the STATE is DOWN.
> +# the forwarding flag should be false, due to the demand_rx_bfd.
>  BFD_CHECK([p0], [false], [false], [none], [down], [No Diagnostic], [none], 
> [down], [No Diagnostic])
> -BFD_CHECK_TX([p0], [1000ms], [1000ms], [0ms])
> -BFD_CHECK_RX([p0], [500ms], [500ms], [1ms])
>
>  AT_CHECK([ovs-vsctl del-br br1], [0], [ignore])
>  AT_CLEANUP
> @@ -605,6 +597,74 @@ BFD_CHECK_RX([p0], [1000ms], [1000ms], [300ms])
>  AT_CHECK([ovs-vsctl del-br br1], [0], [ignore])
>  AT_CLEANUP
>
> +# forwarding_if_rx Test4
> +# Test4 is for testing the demand_rx_bfd feature.
> +# bfd is enabled on both ends of the link.
> +AT_SETUP([bfd - bfd forwarding_if_rx - demand_rx_bfd])
> +OVS_VSWITCHD_START([add-br br1 -- set bridge br1 datapath-type=dummy -- \
> +                    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 bfd:enable=true bfd:min_tx=300 
> bfd:min_rx=300 bfd:forwarding_if_rx=true -- \
> +                    set Interface p1 bfd:enable=true bfd:min_tx=500 
> bfd:min_rx=500])
> +
> +ovs-appctl time/stop
> +# advance the clock, to stablize the states.
> +for i in `seq 0 19`; do ovs-appctl time/warp 500; done
> +BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [none], 
> [up], [No Diagnostic])
> +BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [none], 
> [up], [No Diagnostic])
> +BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
> +
> +# disable the bfd on p1.
> +AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=false], [0])
> +
> +# advance clock by 4000ms, while receiving packets.
> +# the STATE should go DOWN, due to Control Detection Time Expired.
> +# but forwarding flag should be still true.
> +for i in `seq 0 7`
> +do
> +    ovs-appctl time/warp 500
> +    AT_CHECK([ovs-ofctl packet-out br1 3 2  
> "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
> +             [0], [stdout], [])
> +done
> +BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time 
> Expired], [none], [down], [No Diagnostic])
> +
> +# advance clock long enough to trigger the demand_bfd_rx interval
> +# (100 * bfd->cfm_min_rx), forwarding flag should go down since there
> +# is no bfd control packet received during the demand_rx_bfd.
> +for i in `seq 0 120`
> +do
> +    ovs-appctl time/warp 300
> +    AT_CHECK([ovs-ofctl packet-out br1 3 2  
> "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
> +             [0], [stdout], [])
> +done
> +BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time 
> Expired], [none], [down], [No Diagnostic])
> +
> +# now enable the bfd on p1 again.
> +AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=true], [0])
> +# advance clock by 5000ms.  and p1 and p0 should be all up.
> +for i in `seq 0 9`; do ovs-appctl time/warp 500; done
> +BFD_CHECK([p0], [true], [false], [none], [up], [Control Detection Time 
> Expired], [none], [up], [No Diagnostic])
> +BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [none], 
> [up], [Control Detection Time Expired])
> +BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
> +
> +# disable the bfd on p1 again.
> +AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=false], [0])
> +# advance clock long enough to trigger the demand_rx_bfd,
> +# forwarding flag should go down since there is no bfd control packet
> +# received during the demand_rx_bfd.
> +for i in `seq 0 120`
> +do
> +    ovs-appctl time/warp 300
> +    AT_CHECK([ovs-ofctl packet-out br1 3 2  
> "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
> +             [0], [stdout], [])
> +done
> +BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time 
> Expired], [none], [down], [No Diagnostic])
> +
> +AT_CHECK([ovs-vsctl del-br br1], [0], [ignore])
> +AT_CLEANUP
> +
>  # test bfd:flap_count.
>  # This test contains three part:
>  # part 1. tests the flap_count on normal bfd monitored link.
> @@ -683,6 +743,7 @@ BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), 
> forwarding.*$/\1/p"], ["1"]
>
>  # Part-3 now turn on forwarding_if_rx.
>  AT_CHECK([ovs-vsctl set Interface p0 bfd:forwarding_if_rx=true], [0])
> +for i in `seq 0 10`; do ovs-appctl time/warp 100; done
>  # disable the bfd on p1.
>  AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=false], [0])
>
> @@ -699,9 +760,9 @@ BFD_CHECK([p0], [true], [false], [none], [down], [Control 
> Detection Time Expired
>  # flap_count should remain unchanged.
>  BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], 
> ["5"])
>
> -# stop the traffic for 4000ms, the forwarding flag of p0 should turn false.
> +# stop the traffic for more than 100 * bfd->cfm_min_rx ms, the forwarding 
> flag of p0 should turn false.
>  # and there should be the increment of flap_count.
> -for i in `seq 0 7`; do ovs-appctl time/warp 500; done
> +for i in `seq 0 120`; do ovs-appctl time/warp 100; done
>  BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time 
> Expired], [none], [down], [No Diagnostic])
>  BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], 
> ["6"])
>
> @@ -712,21 +773,15 @@ do
>      AT_CHECK([ovs-ofctl packet-out br1 3 2 
> "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
>               [0], [stdout], [])
>  done
> -BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time 
> Expired], [none], [down], [No Diagnostic])
> -# flap_count should be incremented again.
> -BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], 
> ["7"])
> -
> -# stop the traffic for 4000ms, the forwarding flag of p0 should turn false.
> -# and there should be the increment of flap_count.
> -for i in `seq 0 7`; do ovs-appctl time/warp 500; done
> +# forwarding should be false, since there is still no bfd control packet 
> received.
>  BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time 
> Expired], [none], [down], [No Diagnostic])
> -BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], 
> ["8"])
> +BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], 
> ["6"])
>
>  # turn on the bfd on p1.
>  AT_CHECK([ovs-vsctl set interface p1 bfd:enable=true])
>  for i in `seq 0 49`; do ovs-appctl time/warp 100; done
>  # even though there is no data traffic, since p1 bfd is on again, should 
> increment the flap_count.
> -BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], 
> ["9"])
> +BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], 
> ["7"])
>  BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], 
> ["1"])
>
>  OVS_VSWITCHD_STOP
> diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
> index 91dfdf9..d17da50 100644
> --- a/vswitchd/vswitch.xml
> +++ b/vswitchd/vswitch.xml
> @@ -1968,10 +1968,13 @@
>         </column>
>
>         <column name="bfd" key="forwarding_if_rx" type='{"type": "boolean"}'>
> -          True to consider the interface capable of packet I/O as long as it
> -          continues to receive any packets (not just BFD packets).  This
> -          prevents link congestion that causes consecutive BFD control 
> packets
> -          to be lost from marking the interface down.
> +          When <code>true</code>, traffic received on the
> +          <ref table="Interface"/> is used to indicate the capability of 
> packet
> +          I/O.  BFD control packets are still transmitted and received.  At
> +          least one BFD control packet must be received every 100 * <ref
> +          column="bfd" key="min_rx"/> amount of time.  Otherwise, even if
> +          traffic are received, the <ref column="bfd" key="forwarding"/>
> +          will be <code>false</code>.
>         </column>
>
>         <column name="bfd" key="cpath_down" type='{"type": "boolean"}'>
> --
> 1.7.9.5
>
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to