This commit adds a new module ofproto-dpif-monitor in ofproto
directory.  This module is in charge of all monitoring logics,
including bfd and cfm.  Accordingly, the bfd and cfm references
are removed from ofproto-dpif and ofproto-dpif-xlate modules.
And they will invoke the corresponding functions in
ofproto-dpif-monitor module for bfd/cfm configuration.

Signed-off-by: Alex Wang <[email protected]>
---
 ofproto/automake.mk            |    2 +
 ofproto/ofproto-dpif-monitor.c |  397 ++++++++++++++++++++++++++++++++++++++++
 ofproto/ofproto-dpif-monitor.h |   60 ++++++
 ofproto/ofproto-dpif-xlate.c   |   27 +--
 ofproto/ofproto-dpif-xlate.h   |    4 +-
 ofproto/ofproto-dpif.c         |  160 +++-------------
 ofproto/ofproto-dpif.h         |    2 +
 tests/bfd.at                   |  261 --------------------------
 8 files changed, 497 insertions(+), 416 deletions(-)
 create mode 100644 ofproto/ofproto-dpif-monitor.c
 create mode 100644 ofproto/ofproto-dpif-monitor.h

diff --git a/ofproto/automake.mk b/ofproto/automake.mk
index 47ca1b8..432f083 100644
--- a/ofproto/automake.mk
+++ b/ofproto/automake.mk
@@ -28,6 +28,8 @@ ofproto_libofproto_a_SOURCES = \
        ofproto/ofproto-dpif-ipfix.h \
        ofproto/ofproto-dpif-mirror.c \
        ofproto/ofproto-dpif-mirror.h \
+       ofproto/ofproto-dpif-monitor.c \
+       ofproto/ofproto-dpif-monitor.h \
        ofproto/ofproto-dpif-sflow.c \
        ofproto/ofproto-dpif-sflow.h \
        ofproto/ofproto-dpif-upcall.c \
diff --git a/ofproto/ofproto-dpif-monitor.c b/ofproto/ofproto-dpif-monitor.c
new file mode 100644
index 0000000..8f18440
--- /dev/null
+++ b/ofproto/ofproto-dpif-monitor.c
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "ofproto-dpif-monitor.h"
+
+#include <errno.h>
+#include "bfd.h"
+#include "cfm.h"
+#include "hash.h"
+#include "hmap.h"
+#include "ofpbuf.h"
+#include "ofproto.h"
+#include "ofproto-dpif.h"
+#include "util.h"
+#include "vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(ofproto_dpif_monitor);
+
+/* Monitor struct. */
+struct monitor {
+    struct hmap hmap;        /* hmap that contains all port monitors. */
+};
+
+/* Monitored port.  It has reference to bfd/cfm struct of the port. */
+struct mport {
+    struct hmap_node hmap_node;    /* In monitor's hmap. */
+
+    /* Reference to bfd/cfm structs. */
+    struct cfm *cfm;
+    struct bfd *bfd;
+
+    /* Related to sending control packets. */
+    const struct ofport_dpif *ofport;
+    uint8_t *hw_addr;
+};
+
+static struct monitor monitor;
+
+static void ofproto_dpif_monitor_init(void);
+
+static struct mport *mport_create(const struct ofport_dpif *);
+static void mport_check_delete(struct mport *);
+static void mport_delete(struct mport *);
+static struct mport *mport_find(const struct ofport_dpif *);
+
+/* Initializes the monitor struct. */
+static void
+ofproto_dpif_monitor_init(void) {
+    hmap_init(&monitor.hmap);
+}
+
+
+/* Creates a new mport and inserts it into monitor->hmap. */
+static struct mport *
+mport_create(const struct ofport_dpif *ofport)
+{
+    struct mport *mport;
+
+    mport = xmalloc(sizeof *mport);
+    mport->ofport = ofport;
+    mport->bfd = NULL;
+    mport->cfm = NULL;
+    mport->hw_addr = NULL;
+    hmap_insert(&monitor.hmap, &mport->hmap_node, hash_pointer(ofport, 0));
+    return mport;
+}
+
+/* Checkes 'mport', if both bfd and cfm are NULL, deletes the 'mport'. */
+static void
+mport_check_delete(struct mport *mport)
+{
+    if (!mport) {
+        return;
+    }
+
+    if (!mport->bfd && !mport->cfm) {
+        mport_delete(mport);
+    }
+}
+
+/* Removes 'mport' from monitor's hmap and frees it. */
+static void
+mport_delete(struct mport *mport)
+{
+    hmap_remove(&monitor.hmap, &mport->hmap_node);
+    free(mport);
+}
+
+/* Tries finding and returning the 'mport' from the monitor's hash map.
+ * If there is no such 'mport', returns NULL. */
+static struct mport *
+mport_find(const struct ofport_dpif *ofport)
+{
+    struct mport *mport = NULL;
+    struct mport *node;
+
+    HMAP_FOR_EACH_WITH_HASH (node, hmap_node, hash_pointer(ofport, 0),
+                             &monitor.hmap) {
+        if (node->ofport == ofport) {
+            mport = node;
+            break;
+        }
+    }
+    return mport;
+}
+
+
+/* Checks bfd and cfm status to determine if the port is capable of
+ * forwarding data traffic.  If bfd and cfm are not configured,
+ * return true. */
+bool
+ofproto_dpif_monitor_check_alive(const struct ofport_dpif *ofport)
+{
+    struct mport *mport = mport_find(ofport);
+    bool cfm_enable = false;
+    bool bfd_enable = false;
+
+    if (!mport) {
+        return true;
+    }
+
+    if (mport->cfm) {
+        int cfm_opup = cfm_get_opup(mport->cfm);
+
+        cfm_enable = !cfm_get_fault(mport->cfm);
+
+        if (cfm_opup >= 0) {
+            cfm_enable = cfm_enable && cfm_opup;
+        }
+    }
+    if (mport->bfd) {
+        bfd_enable = bfd_forwarding(mport->bfd);
+    }
+    return cfm_enable || bfd_enable;
+}
+
+/* Checks if the bfd flow should be processed. */
+bool
+ofproto_dpif_monitor_should_process_bfd(const struct ofport_dpif *ofport,
+                                        const struct flow *flow,
+                                        struct flow_wildcards *wc)
+{
+    struct mport *mport = mport_find(ofport);
+
+    if (mport && mport->bfd) {
+        return bfd_should_process_flow(mport->bfd, flow, wc);
+    }
+    return false;
+}
+
+/* Checks if the cfm flow should be processed. */
+bool
+ofproto_dpif_monitor_should_process_cfm(const struct ofport_dpif *ofport,
+                                        const struct flow *flow,
+                                        struct flow_wildcards *wc)
+{
+    struct mport *mport = mport_find(ofport);
+
+    if (mport && mport->cfm) {
+        return cfm_should_process_flow(mport->cfm, flow, wc);
+    }
+    return false;
+}
+
+/* Processes the bfd flow. */
+void
+ofproto_dpif_monitor_process_bfd(const struct ofport_dpif *ofport,
+                                 const struct flow *flow,
+                                 const struct ofpbuf *packet)
+{
+    struct mport *mport = mport_find(ofport);
+    if (mport) {
+        bfd_process_packet(mport->bfd, flow, packet);
+    }
+}
+
+/* Processes the CFM control packet. */
+void
+ofproto_dpif_monitor_process_cfm(const struct ofport_dpif *ofport,
+                                 const struct ofpbuf *packet)
+{
+    struct mport *mport = mport_find(ofport);
+    if (mport) {
+        cfm_process_heartbeat(mport->cfm, packet);
+    }
+}
+
+/* Starts the monitor, makes sure the init() function is called only once. */
+void
+ofproto_dpif_monitor_start(void)
+{
+    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
+
+    if (ovsthread_once_start(&once)) {
+        ofproto_dpif_monitor_init();
+        ovsthread_once_done(&once);
+    }
+}
+
+/* Sets bfd on ofport.  Returns 1 if new bfd struct is created or deleted,
+ * and 0 if bfd is reconfigured. */
+int
+ofproto_dpif_monitor_set_bfd(const struct ofport_dpif *ofport,
+                             const struct smap *cfg,
+                             struct netdev *netdev,  uint8_t *hw_addr)
+{
+    struct mport *mport = mport_find(ofport);
+    struct bfd *old_bfd, *new_bfd;
+    int retval = 0;
+
+    old_bfd  = mport ? mport->bfd : NULL;
+    new_bfd = bfd_configure(old_bfd, netdev_get_name(netdev), cfg, netdev);
+
+    if (old_bfd != new_bfd) {
+        if (!old_bfd) {
+            /* New bfd struct created. */
+            if (!mport) {
+                mport = mport_create(ofport);
+                mport->hw_addr = hw_addr;
+            }
+            mport->bfd = new_bfd;
+        } else {
+            /* bfd struct deleted. */
+            mport->bfd = new_bfd;
+            mport_check_delete(mport);
+        }
+        retval = 1;
+    }
+
+    return retval;
+}
+
+/* Sets cfm on ofport.  Returns 1 if new cfm struct is created or deleted,
+ * 0 if cfm is reconfigured or -EINVAL if there is an error. */
+int
+ofproto_dpif_monitor_set_cfm(const struct ofport_dpif *ofport,
+                             const struct cfm_settings *s,
+                             struct netdev *netdev, uint8_t *hw_addr)
+{
+    struct mport *mport = mport_find(ofport);
+    int retval = 0;
+
+    if (s) {
+        if (!mport) {
+            mport = mport_create(ofport);
+            mport->hw_addr = hw_addr;
+        }
+        if (!mport->cfm) {
+            mport->cfm = cfm_create(netdev);
+            retval = 1;
+        }
+        if (cfm_configure(mport->cfm, s)) {
+            return retval;
+        }
+    }
+
+    /* If reaches here, either 's' is NULL or cfm_configure()
+     * returns false. */
+    if (mport) {
+        cfm_unref(mport->cfm);
+        mport->cfm = NULL;
+        mport_check_delete(mport);
+    }
+
+    retval = -EINVAL;
+    return retval;
+}
+
+/* Extracts the bfd status and stores it in 'smap'. */
+int
+ofproto_dpif_monitor_get_bfd_status(const struct ofport_dpif *ofport,
+                                    struct smap *smap)
+{
+    struct mport *mport = mport_find(ofport);
+
+    if (!mport || !mport->bfd) {
+        return ENOENT;
+    }
+    bfd_get_status(mport->bfd, smap);
+
+    return 0;
+}
+
+/* Extracts the cfm status and stores it in 'status'. */
+bool
+ofproto_dpif_monitor_get_cfm_status(const struct ofport_dpif *ofport,
+                                    struct ofproto_cfm_status *status)
+{
+    struct mport *mport = mport_find(ofport);
+
+    if (!mport || !mport->cfm) {
+        return false;
+    }
+    status->faults = cfm_get_fault(mport->cfm);
+    status->remote_opstate = cfm_get_opup(mport->cfm);
+    status->health = cfm_get_health(mport->cfm);
+    cfm_get_remote_mpids(mport->cfm, &status->rmps, &status->n_rmps);
+    return true;
+}
+
+
+/* Updates the netdev and hw_addr. */
+void
+ofproto_dpif_monitor_set_netdev(const struct ofport_dpif *ofport,
+                                struct netdev *netdev,
+                                uint8_t *hw_addr)
+{
+    struct mport *mport = mport_find(ofport);
+
+    if (!mport) {
+        return;
+    } else {
+        mport->hw_addr = hw_addr;
+        if (mport->bfd) {
+            bfd_set_netdev(mport->bfd, netdev);
+        }
+        if (mport->cfm) {
+            cfm_set_netdev(mport->cfm, netdev);
+        }
+    }
+}
+
+/* Checks the sending of control packets on all mports.  Sends the control
+ * packets if needed. */
+void
+ofproto_dpif_monitor_run_fast(void)
+{
+    struct mport *mport;
+
+    HMAP_FOR_EACH (mport, hmap_node, &monitor.hmap) {
+        if (mport->cfm && cfm_should_send_ccm(mport->cfm)) {
+            struct ofpbuf packet;
+
+            ofpbuf_init(&packet, 0);
+            cfm_compose_ccm(mport->cfm, &packet, mport->hw_addr);
+            ofproto_dpif_send_packet(mport->ofport, &packet);
+            ofpbuf_uninit(&packet);
+        }
+
+        if (mport->bfd && bfd_should_send_packet(mport->bfd)) {
+            struct ofpbuf packet;
+
+            ofpbuf_init(&packet, 0);
+            bfd_put_packet(mport->bfd, &packet, mport->hw_addr);
+            ofproto_dpif_send_packet(mport->ofport, &packet);
+            ofpbuf_uninit(&packet);
+        }
+    }
+}
+
+/* Executes bfd_run(), cfm_run() on all mports. */
+void
+ofproto_dpif_monitor_run(void)
+{
+    struct mport *mport;
+
+    HMAP_FOR_EACH (mport, hmap_node, &monitor.hmap) {
+        if (mport->cfm) {
+            cfm_run(mport->cfm);
+        }
+
+        if (mport->bfd) {
+            bfd_run(mport->bfd);
+        }
+    }
+}
+
+/* Executes the bfd_wait() and cfm_wait() functions on all mports. */
+void
+ofproto_dpif_monitor_wait(void)
+{
+    struct mport *mport;
+
+    HMAP_FOR_EACH (mport, hmap_node, &monitor.hmap) {
+        if (mport->cfm) {
+            cfm_wait(mport->cfm);
+        }
+
+        if (mport->bfd) {
+            bfd_wait(mport->bfd);
+        }
+    }
+}
diff --git a/ofproto/ofproto-dpif-monitor.h b/ofproto/ofproto-dpif-monitor.h
new file mode 100644
index 0000000..169973e
--- /dev/null
+++ b/ofproto/ofproto-dpif-monitor.h
@@ -0,0 +1,60 @@
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License. */
+
+#ifndef OFPROTO_DPIF_MONITOR_H
+#define OFPROTO_DPIF_MONITOR_H 1
+
+#include "ofp-util.h"
+
+struct bfd;
+struct cfm;
+struct cfm_settings;
+struct flow;
+struct ofpbuf;
+struct ofproto_cfm_status;
+struct ofport_dpif;
+
+void ofproto_dpif_monitor_start(void);
+void ofproto_dpif_monitor_run(void);
+void ofproto_dpif_monitor_run_fast(void);
+void ofproto_dpif_monitor_wait(void);
+
+bool ofproto_dpif_monitor_check_alive(const struct ofport_dpif *ofport);
+
+void ofproto_dpif_monitor_process_bfd(const struct ofport_dpif *ofport,
+                                      const struct flow *flow,
+                                      const struct ofpbuf *packet);
+void ofproto_dpif_monitor_process_cfm(const struct ofport_dpif *ofport,
+                                      const struct ofpbuf *packet);
+bool ofproto_dpif_monitor_should_process_bfd(const struct ofport_dpif *ofport,
+                                             const struct flow *flow,
+                                             struct flow_wildcards *wc);
+bool ofproto_dpif_monitor_should_process_cfm(const struct ofport_dpif *ofport,
+                                             const struct flow *flow,
+                                             struct flow_wildcards *wc);
+
+int ofproto_dpif_monitor_get_bfd_status(const struct ofport_dpif *,
+                                        struct smap *);
+bool ofproto_dpif_monitor_get_cfm_status(const struct ofport_dpif *,
+                                         struct ofproto_cfm_status *);
+int ofproto_dpif_monitor_set_bfd(const struct ofport_dpif *,
+                                 const struct smap *,
+                                 struct netdev *, uint8_t *);
+int ofproto_dpif_monitor_set_cfm(const struct ofport_dpif *,
+                                 const struct cfm_settings *,
+                                 struct netdev *, uint8_t *);
+void ofproto_dpif_monitor_set_netdev(const struct ofport_dpif *,
+                                     struct netdev *,
+                                     uint8_t *);
+#endif /* ofproto-dpif-monitor.h */
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index a5b6814..5d9297e 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -18,12 +18,10 @@
 
 #include <errno.h>
 
-#include "bfd.h"
 #include "bitmap.h"
 #include "bond.h"
 #include "bundle.h"
 #include "byte-order.h"
-#include "cfm.h"
 #include "connmgr.h"
 #include "coverage.h"
 #include "dpif.h"
@@ -42,6 +40,7 @@
 #include "ofp-actions.h"
 #include "ofproto/ofproto-dpif-ipfix.h"
 #include "ofproto/ofproto-dpif-mirror.h"
+#include "ofproto/ofproto-dpif-monitor.h"
 #include "ofproto/ofproto-dpif-sflow.h"
 #include "ofproto/ofproto-dpif.h"
 #include "ofproto/ofproto-provider.h"
@@ -128,9 +127,6 @@ struct xport {
 
     bool may_enable;                 /* May be enabled in bonds. */
     bool is_tunnel;                  /* Is a tunnel port. */
-
-    struct cfm *cfm;                 /* CFM handle or null. */
-    struct bfd *bfd;                 /* BFD handle or null. */
 };
 
 struct xlate_ctx {
@@ -368,7 +364,6 @@ void
 xlate_ofport_set(struct ofproto_dpif *ofproto, struct ofbundle *ofbundle,
                  struct ofport_dpif *ofport, ofp_port_t ofp_port,
                  odp_port_t odp_port, const struct netdev *netdev,
-                 const struct cfm *cfm, const struct bfd *bfd,
                  struct ofport_dpif *peer, int stp_port_no,
                  const struct ofproto_port_queue *qdscp_list, size_t n_qdscp,
                  enum ofputil_port_config config, bool is_tunnel,
@@ -402,16 +397,6 @@ xlate_ofport_set(struct ofproto_dpif *ofproto, struct 
ofbundle *ofbundle,
         xport->netdev = netdev_ref(netdev);
     }
 
-    if (xport->cfm != cfm) {
-        cfm_unref(xport->cfm);
-        xport->cfm = cfm_ref(cfm);
-    }
-
-    if (xport->bfd != bfd) {
-        bfd_unref(xport->bfd);
-        xport->bfd = bfd_ref(bfd);
-    }
-
     if (xport->peer) {
         xport->peer->peer = NULL;
     }
@@ -471,8 +456,6 @@ xlate_ofport_remove(struct ofport_dpif *ofport)
     hmap_remove(&xport->xbridge->xports, &xport->ofp_node);
 
     netdev_close(xport->netdev);
-    cfm_unref(xport->cfm);
-    bfd_unref(xport->bfd);
     free(xport);
 }
 
@@ -1493,14 +1476,14 @@ process_special(struct xlate_ctx *ctx, const struct 
flow *flow,
 
     if (!xport) {
         return 0;
-    } else if (xport->cfm && cfm_should_process_flow(xport->cfm, flow, wc)) {
+    } else if (ofproto_dpif_monitor_should_process_cfm(xport->ofport, flow, 
wc)) {
         if (packet) {
-            cfm_process_heartbeat(xport->cfm, packet);
+            ofproto_dpif_monitor_process_cfm(xport->ofport, packet);
         }
         return SLOW_CFM;
-    } else if (xport->bfd && bfd_should_process_flow(xport->bfd, flow, wc)) {
+    } else if (ofproto_dpif_monitor_should_process_bfd(xport->ofport, flow, 
wc)) {
         if (packet) {
-            bfd_process_packet(xport->bfd, flow, packet);
+            ofproto_dpif_monitor_process_bfd(xport->ofport, flow, packet);
         }
         return SLOW_BFD;
     } else if (xport->xbundle && xport->xbundle->lacp
diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h
index a54a9e4..8768ad3 100644
--- a/ofproto/ofproto-dpif-xlate.h
+++ b/ofproto/ofproto-dpif-xlate.h
@@ -24,7 +24,6 @@
 #include "ofproto.h"
 #include "stp.h"
 
-struct bfd;
 struct bond;
 struct dpif;
 struct lacp;
@@ -133,8 +132,7 @@ void xlate_bundle_remove(struct ofbundle *) 
OVS_REQ_WRLOCK(xlate_rwlock);
 
 void xlate_ofport_set(struct ofproto_dpif *, struct ofbundle *,
                       struct ofport_dpif *, ofp_port_t, odp_port_t,
-                      const struct netdev *, const struct cfm *,
-                      const struct bfd *, struct ofport_dpif *peer,
+                      const struct netdev *, struct ofport_dpif *peer,
                       int stp_port_no, const struct ofproto_port_queue *qdscp,
                       size_t n_qdscp, enum ofputil_port_config, bool is_tunnel,
                       bool may_enable) OVS_REQ_WRLOCK(xlate_rwlock);
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 80874b8..ee107a9 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -21,13 +21,11 @@
 
 #include <errno.h>
 
-#include "bfd.h"
 #include "bond.h"
 #include "bundle.h"
 #include "byte-order.h"
 #include "connmgr.h"
 #include "coverage.h"
-#include "cfm.h"
 #include "dpif.h"
 #include "dynamic-string.h"
 #include "fail-open.h"
@@ -52,6 +50,7 @@
 #include "ofproto-dpif-governor.h"
 #include "ofproto-dpif-ipfix.h"
 #include "ofproto-dpif-mirror.h"
+#include "ofproto-dpif-monitor.h"
 #include "ofproto-dpif-sflow.h"
 #include "ofproto-dpif-upcall.h"
 #include "ofproto-dpif-xlate.h"
@@ -304,8 +303,6 @@ struct ofport_dpif {
     odp_port_t odp_port;
     struct ofbundle *bundle;    /* Bundle that contains this port, if any. */
     struct list bundle_node;    /* In struct ofbundle's "ports" list. */
-    struct cfm *cfm;            /* Connectivity Fault Management, if any. */
-    struct bfd *bfd;            /* BFD, if any. */
     bool may_enable;            /* May be enabled in bonds. */
     bool is_tunnel;             /* This port is a tunnel. */
     long long int carrier_seq;  /* Carrier status changes. */
@@ -360,8 +357,6 @@ ofport_dpif_cast(const struct ofport *ofport)
 }
 
 static void port_run(struct ofport_dpif *);
-static void port_run_fast(struct ofport_dpif *);
-static void port_wait(struct ofport_dpif *);
 static int set_bfd(struct ofport *, const struct smap *);
 static int set_cfm(struct ofport *, const struct cfm_settings *);
 static void ofport_update_peer(struct ofport_dpif *);
@@ -540,9 +535,6 @@ static int expire(struct dpif_backer *);
 /* NetFlow. */
 static void send_netflow_active_timeouts(struct ofproto_dpif *);
 
-/* Utilities. */
-static int send_packet(const struct ofport_dpif *, struct ofpbuf *packet);
-
 /* Global variables. */
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
@@ -816,8 +808,7 @@ type_run(const char *type)
                     : -1;
                 xlate_ofport_set(ofproto, ofport->bundle, ofport,
                                  ofport->up.ofp_port, ofport->odp_port,
-                                 ofport->up.netdev, ofport->cfm,
-                                 ofport->bfd, ofport->peer, stp_port,
+                                 ofport->up.netdev, ofport->peer, stp_port,
                                  ofport->qdscp, ofport->n_qdscp,
                                  ofport->up.pp.config, ofport->is_tunnel,
                                  ofport->may_enable);
@@ -1244,6 +1235,8 @@ construct(struct ofproto *ofproto_)
         return error;
     }
 
+    ofproto_dpif_monitor_start();
+
     max_ports = dpif_get_max_ports(ofproto->backer->dpif);
     ofproto_init_max_ports(ofproto_, MIN(max_ports, ofp_to_u16(OFPP_MAX)));
 
@@ -1452,7 +1445,6 @@ run_fast(struct ofproto *ofproto_)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
     struct ofputil_packet_in *pin, *next_pin;
-    struct ofport_dpif *ofport;
     struct list pins;
 
     /* Do not perform any periodic activity required by 'ofproto' while
@@ -1468,10 +1460,7 @@ run_fast(struct ofproto *ofproto_)
         free(CONST_CAST(void *, pin->packet));
         free(pin);
     }
-
-    HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
-        port_run_fast(ofport);
-    }
+    ofproto_dpif_monitor_run_fast();
 
     return 0;
 }
@@ -1514,6 +1503,8 @@ run(struct ofproto *ofproto_)
         dpif_ipfix_run(ofproto->ipfix);
     }
 
+    ofproto_dpif_monitor_run_fast();
+    ofproto_dpif_monitor_run();
     HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
         port_run(ofport);
     }
@@ -1558,7 +1549,6 @@ static void
 wait(struct ofproto *ofproto_)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
-    struct ofport_dpif *ofport;
     struct ofbundle *bundle;
 
     if (ofproto_get_flow_restore_wait()) {
@@ -1571,9 +1561,8 @@ wait(struct ofproto *ofproto_)
     if (ofproto->ipfix) {
         dpif_ipfix_wait(ofproto->ipfix);
     }
-    HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
-        port_wait(ofport);
-    }
+
+    ofproto_dpif_monitor_wait();
     HMAP_FOR_EACH (bundle, hmap_node, &ofproto->bundles) {
         bundle_wait(bundle);
     }
@@ -1708,8 +1697,6 @@ port_construct(struct ofport *port_)
 
     ofproto->backer->need_revalidate = REV_RECONFIGURE;
     port->bundle = NULL;
-    port->cfm = NULL;
-    port->bfd = NULL;
     port->may_enable = true;
     port->stp_port = NULL;
     port->stp_state = STP_DISABLED;
@@ -1828,13 +1815,7 @@ port_modified(struct ofport *port_)
         bond_slave_set_netdev(port->bundle->bond, port, port->up.netdev);
     }
 
-    if (port->cfm) {
-        cfm_set_netdev(port->cfm, port->up.netdev);
-    }
-
-    if (port->bfd) {
-        bfd_set_netdev(port->bfd, port->up.netdev);
-    }
+    ofproto_dpif_monitor_set_netdev(port, port->up.netdev, 
port->up.pp.hw_addr);
 
     if (port->is_tunnel && tnl_port_reconfigure(port, port->up.netdev,
                                                 port->odp_port)) {
@@ -1926,27 +1907,17 @@ static int
 set_cfm(struct ofport *ofport_, const struct cfm_settings *s)
 {
     struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
+    struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport_->ofproto);
     int error;
 
-    if (!s) {
+    error = ofproto_dpif_monitor_set_cfm(ofport, s, ofport->up.netdev,
+                                         ofport->up.pp.hw_addr);
+    if (error > 0) {
         error = 0;
-    } else {
-        if (!ofport->cfm) {
-            struct ofproto_dpif *ofproto;
-
-            ofproto = ofproto_dpif_cast(ofport->up.ofproto);
-            ofproto->backer->need_revalidate = REV_RECONFIGURE;
-            ofport->cfm = cfm_create(ofport->up.netdev);
-        }
-
-        if (cfm_configure(ofport->cfm, s)) {
-            return 0;
-        }
-
-        error = EINVAL;
+        ofproto->backer->need_revalidate = REV_RECONFIGURE;
+    } else if (error < 0) {
+        error = -error;
     }
-    cfm_unref(ofport->cfm);
-    ofport->cfm = NULL;
     return error;
 }
 
@@ -1956,15 +1927,7 @@ get_cfm_status(const struct ofport *ofport_,
 {
     struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
 
-    if (ofport->cfm) {
-        status->faults = cfm_get_fault(ofport->cfm);
-        status->remote_opstate = cfm_get_opup(ofport->cfm);
-        status->health = cfm_get_health(ofport->cfm);
-        cfm_get_remote_mpids(ofport->cfm, &status->rmps, &status->n_rmps);
-        return true;
-    } else {
-        return false;
-    }
+    return ofproto_dpif_monitor_get_cfm_status(ofport, status);
 }
 
 static int
@@ -1972,15 +1935,14 @@ set_bfd(struct ofport *ofport_, const struct smap *cfg)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport_->ofproto);
     struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
-    struct bfd *old;
+    int error;
 
-    old = ofport->bfd;
-    ofport->bfd = bfd_configure(old, netdev_get_name(ofport->up.netdev),
-                                cfg, ofport->up.netdev);
-    if (ofport->bfd != old) {
+    error = ofproto_dpif_monitor_set_bfd(ofport, cfg, ofport->up.netdev,
+                                         ofport->up.pp.hw_addr);
+    if (error > 0) {
+        error = 0;
         ofproto->backer->need_revalidate = REV_RECONFIGURE;
     }
-
     return 0;
 }
 
@@ -1989,12 +1951,7 @@ get_bfd_status(struct ofport *ofport_, struct smap *smap)
 {
     struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
 
-    if (ofport->bfd) {
-        bfd_get_status(ofport->bfd, smap);
-        return 0;
-    } else {
-        return ENOENT;
-    }
+    return ofproto_dpif_monitor_get_bfd_status(ofport, smap);
 }
 
 /* Spanning Tree. */
@@ -2018,7 +1975,7 @@ send_bpdu_cb(struct ofpbuf *pkt, int port_num, void 
*ofproto_)
             VLOG_WARN_RL(&rl, "%s: cannot send BPDU on port %d "
                          "with unknown MAC", ofproto->up.name, port_num);
         } else {
-            send_packet(ofport, pkt);
+            ofproto_dpif_send_packet(ofport, pkt);
         }
     }
     ofpbuf_delete(pkt);
@@ -2614,7 +2571,7 @@ send_pdu_cb(void *port_, const void *pdu, size_t pdu_size)
                                  pdu_size);
         memcpy(packet_pdu, pdu, pdu_size);
 
-        send_packet(port, &packet);
+        ofproto_dpif_send_packet(port, &packet);
         ofpbuf_uninit(&packet);
     } else {
         VLOG_ERR_RL(&rl, "port %s: cannot obtain Ethernet address of iface "
@@ -2651,7 +2608,7 @@ bundle_send_learning_packets(struct ofbundle *bundle)
     LIST_FOR_EACH (learning_packet, list_node, &packets) {
         int ret;
 
-        ret = send_packet(learning_packet->private_p, learning_packet);
+        ret = ofproto_dpif_send_packet(learning_packet->private_p, 
learning_packet);
         if (ret) {
             error = ret;
             n_errors++;
@@ -2866,59 +2823,15 @@ ofport_update_peer(struct ofport_dpif *ofport)
 }
 
 static void
-port_run_fast(struct ofport_dpif *ofport)
-{
-    if (ofport->cfm && cfm_should_send_ccm(ofport->cfm)) {
-        struct ofpbuf packet;
-
-        ofpbuf_init(&packet, 0);
-        cfm_compose_ccm(ofport->cfm, &packet, ofport->up.pp.hw_addr);
-        send_packet(ofport, &packet);
-        ofpbuf_uninit(&packet);
-    }
-
-    if (ofport->bfd && bfd_should_send_packet(ofport->bfd)) {
-        struct ofpbuf packet;
-
-        ofpbuf_init(&packet, 0);
-        bfd_put_packet(ofport->bfd, &packet, ofport->up.pp.hw_addr);
-        send_packet(ofport, &packet);
-        ofpbuf_uninit(&packet);
-    }
-}
-
-static void
 port_run(struct ofport_dpif *ofport)
 {
     long long int carrier_seq = netdev_get_carrier_resets(ofport->up.netdev);
     bool carrier_changed = carrier_seq != ofport->carrier_seq;
     bool enable = netdev_get_carrier(ofport->up.netdev);
-    bool cfm_enable = false;
-    bool bfd_enable = false;
 
     ofport->carrier_seq = carrier_seq;
 
-    port_run_fast(ofport);
-
-    if (ofport->cfm) {
-        int cfm_opup = cfm_get_opup(ofport->cfm);
-
-        cfm_run(ofport->cfm);
-        cfm_enable = !cfm_get_fault(ofport->cfm);
-
-        if (cfm_opup >= 0) {
-            cfm_enable = cfm_enable && cfm_opup;
-        }
-    }
-
-    if (ofport->bfd) {
-        bfd_run(ofport->bfd);
-        bfd_enable = bfd_forwarding(ofport->bfd);
-    }
-
-    if (ofport->bfd || ofport->cfm) {
-        enable = enable && (cfm_enable || bfd_enable);
-    }
+    enable = enable && ofproto_dpif_monitor_check_alive(ofport);
 
     if (ofport->bundle) {
         enable = enable && lacp_slave_may_enable(ofport->bundle->lacp, ofport);
@@ -2926,7 +2839,6 @@ port_run(struct ofport_dpif *ofport)
             lacp_slave_carrier_changed(ofport->bundle->lacp, ofport);
         }
     }
-
     if (ofport->may_enable != enable) {
         struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport->up.ofproto);
         ofproto->backer->need_revalidate = REV_PORT_TOGGLED;
@@ -2935,18 +2847,6 @@ port_run(struct ofport_dpif *ofport)
     ofport->may_enable = enable;
 }
 
-static void
-port_wait(struct ofport_dpif *ofport)
-{
-    if (ofport->cfm) {
-        cfm_wait(ofport->cfm);
-    }
-
-    if (ofport->bfd) {
-        bfd_wait(ofport->bfd);
-    }
-}
-
 static int
 port_query_by_name(const struct ofproto *ofproto_, const char *devname,
                    struct ofproto_port *ofproto_port)
@@ -4945,8 +4845,8 @@ rule_modify_actions(struct rule *rule_, bool 
reset_counters)
 /* Sends 'packet' out 'ofport'.
  * May modify 'packet'.
  * Returns 0 if successful, otherwise a positive errno value. */
-static int
-send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
+int
+ofproto_dpif_send_packet(const struct ofport_dpif *ofport, struct ofpbuf 
*packet)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport->up.ofproto);
     uint64_t odp_actions_stub[1024 / 8];
diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
index 14a9669..8727551 100644
--- a/ofproto/ofproto-dpif.h
+++ b/ofproto/ofproto-dpif.h
@@ -95,6 +95,8 @@ bool vsp_adjust_flow(const struct ofproto_dpif *, struct flow 
*);
 
 void ofproto_dpif_send_packet_in(struct ofproto_dpif *,
                                  struct ofputil_packet_in *pin);
+int ofproto_dpif_send_packet(const struct ofport_dpif *ofport,
+                             struct ofpbuf *packet);
 void ofproto_dpif_flow_mod(struct ofproto_dpif *, struct ofputil_flow_mod *);
 
 struct ofport_dpif *odp_port_to_ofport(const struct dpif_backer *, odp_port_t);
diff --git a/tests/bfd.at b/tests/bfd.at
index 0b2b7cc..db6c6f5 100644
--- a/tests/bfd.at
+++ b/tests/bfd.at
@@ -248,267 +248,6 @@ This flow is handled by the userspace slow path because 
it:
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
-# Tests below are for bfd decay features.
-AT_SETUP([bfd - bfd decay])
-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:decay_min_rx=3000 -- \
-                    set Interface p1 bfd:enable=true bfd:min_tx=500 
bfd:min_rx=500])
-
-ovs-appctl time/stop
-
-# wait for local session state to go from down to up.
-for i in `seq 0 1`; do ovs-appctl time/warp 500; done
-BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [none], 
[init], [No Diagnostic])
-
-
-# Test-1 BFD decay: decay to decay_min_rx
-# bfd:decay_min_rx is set to 3000ms after the local state of p0 goes up,
-# so for the first 2500ms, there should be no change.
-for i in `seq 0 4`; do ovs-appctl time/warp 500; done
-BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [none], [up], 
[No Diagnostic])
-BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
-BFD_CHECK_RX([p0], [500ms], [300ms], [500ms])
-
-# advance the clock by 500ms.
-ovs-appctl time/warp 500
-# now at 3000ms, min_rx should decay to 3000ms and there should be
-# poll sequence flags.
-BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [final], [up], 
[No Diagnostic])
-BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [poll], [up], 
[No Diagnostic])
-BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
-BFD_CHECK_RX([p0], [3000ms], [3000ms], [500ms])
-
-# since the tx_min of p0 is still 500ms, after 500ms from decay,
-# the control message will be sent from p0 to p1, and p1 'flag'
-# will go back to none.
-ovs-appctl time/warp 500
-BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [none], [up], 
[No Diagnostic])
-
-# the rx_min of p0 is 3000ms now, and p1 will send next control message
-# 3000ms after decay. so, advance clock by 2500ms to make that happen.
-for i in `seq 0 4`; do ovs-appctl time/warp 500; done
-BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [none], [up], 
[No Diagnostic])
-BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
-BFD_CHECK_RX([p0], [3000ms], [3000ms], [500ms])
-# End of Test-1 ###############################################################
-
-
-# Test-2 BFD decay: go back to cfg_min_rx when there is traffic
-# receive packet at 1/100ms rate for 3000ms.
-for i in `seq 0 30`
-do
-    ovs-appctl time/warp 100
-    AT_CHECK([ovs-ofctl packet-out br1 3 2  
"90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
-             [0], [stdout], [])
-done
-# after a decay interval (3000ms), the p0 min_rx will go back to
-# cfg_min_rx. there should be poll sequence flags.
-BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [final], [up], 
[No Diagnostic])
-BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [poll], [up], 
[No Diagnostic])
-BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
-BFD_CHECK_RX([p0], [500ms], [300ms], [500ms])
-
-# 500ms later, both direction will send control messages,
-# and their 'flag' will go back to none.
-ovs-appctl time/warp 500
-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])
-BFD_CHECK_RX([p0], [500ms], [300ms], [500ms])
-# End of Test-2 ###############################################################
-
-
-# Test-3 BFD decay: go back to cfg_min_rx when decay_min_rx is changed
-# advance the clock by 2500ms to 3000m after restore of
-# min_rx. p0 is decayed, and there should be the poll sequence flags.
-for i in `seq 0 4`; do ovs-appctl time/warp 500; done
-BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [final], [up], 
[No Diagnostic])
-BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [poll], [up], 
[No Diagnostic])
-BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
-BFD_CHECK_RX([p0], [3000ms], [3000ms], [500ms])
-
-# advance the clock, to make 'flag' go back to none.
-for i in `seq 0 5`; 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])
-
-# change decay_min_rx to 1000ms.
-# for decay_min_rx < 2000ms, the decay detection time is set to 2000ms.
-# this should firstly reset the min_rx and start poll sequence.
-AT_CHECK([ovs-vsctl set Interface p0 bfd:decay_min_rx=1000])
-BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [final], [up], 
[No Diagnostic])
-BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [poll], [up], 
[No Diagnostic])
-BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
-BFD_CHECK_RX([p0], [500ms], [300ms], [500ms])
-
-# for the following 1500ms, there should be no decay,
-# since the decay_detect_time is set to 2000ms.
-for i in `seq 0 2`
-do
-    ovs-appctl time/warp 500
-    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])
-    BFD_CHECK_RX([p0], [500ms], [300ms], [500ms])
-done
-
-ovs-appctl time/warp 500
-# at 2000ms, decay should happen and there should be the poll sequence flags.
-BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [final], [up], 
[No Diagnostic])
-BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [poll], [up], 
[No Diagnostic])
-BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
-BFD_CHECK_RX([p0], [1000ms], [1000ms], [500ms])
-# advance the clock, so 'flag' go back to none.
-for i in `seq 0 4`; do ovs-appctl time/warp 500; done
-# End of Test-3 ###############################################################
-
-
-# Test-4 BFD decay: set min_rx to 800ms.
-# this should firstly reset the min_rx and then re-decay to 1000ms.
-AT_CHECK([ovs-vsctl set Interface p0 bfd:min_rx=800])
-BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [final], [up], 
[No Diagnostic])
-BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [poll], [up], 
[No Diagnostic])
-BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
-BFD_CHECK_RX([p0], [800ms], [800ms], [500ms])
-
-# for the following 1600ms, there should be no decay,
-# since the decay detection time is set to 2000ms.
-for i in `seq 0 1`
-do
-    ovs-appctl time/warp 800
-    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])
-    BFD_CHECK_RX([p0], [800ms], [800ms], [500ms])
-done
-
-ovs-appctl time/warp 400
-# at 2000ms, decay should happen and there should be the poll sequence flags.
-BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [final], [up], 
[No Diagnostic])
-BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [poll], [up], 
[No Diagnostic])
-BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
-BFD_CHECK_RX([p0], [1000ms], [1000ms], [500ms])
-# advance the clock, so 'flag' go back to none.
-for i in `seq 0 4`; do ovs-appctl time/warp 500; done
-# End of Test-4 ###############################################################
-
-
-# Test-5 BFD decay: set min_rx to 300ms and decay_min_rx to 5000ms together.
-AT_CHECK([ovs-vsctl set Interface p0 bfd:min_rx=300 bfd:decay_min_rx=5000])
-BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [final], [up], 
[No Diagnostic])
-BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [poll], [up], 
[No Diagnostic])
-BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
-BFD_CHECK_RX([p0], [500ms], [300ms], [500ms])
-
-# for decay_min_rx > 2000ms, the decay detection time is set to
-# decay_min_rx (5000ms).
-# for the following 4500ms, there should be no decay,
-# since the decay detection time is set to 5000ms.
-for i in `seq 0 8`
-do
-    ovs-appctl time/warp 500
-    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])
-    BFD_CHECK_RX([p0], [500ms], [300ms], [500ms])
-done
-
-ovs-appctl time/warp 500
-# at 5000ms, decay should happen and there should be the poll sequence flags.
-BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [final], [up], 
[No Diagnostic])
-BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [poll], [up], 
[No Diagnostic])
-BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
-BFD_CHECK_RX([p0], [5000ms], [5000ms], [500ms])
-# advance the clock, to make 'flag' go back to none.
-for i in `seq 0 9`; do ovs-appctl time/warp 500; done
-# End of Test-5 ###############################################################
-
-
-# Test-6 BFD decay: set decay_min_rx to 0 to disable bfd decay.
-AT_CHECK([ovs-vsctl set Interface p0 bfd:decay_min_rx=0])
-# min_rx is reset, and there should be the poll sequence flags.
-BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [final], [up], 
[No Diagnostic])
-BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [poll], [up], 
[No Diagnostic])
-BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
-BFD_CHECK_RX([p0], [500ms], [300ms], [500ms])
-for i in `seq 0 20`
-do
-    ovs-appctl time/warp 500
-    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])
-    BFD_CHECK_RX([p0], [500ms], [300ms], [500ms])
-done
-# End of Test-6 
################################################################
-
-
-# Test-7 BFD decay: rmt_min_tx is greater than decay_min_rx
-AT_CHECK([ovs-vsctl set Interface p0 bfd:decay_min_rx=3000 -- set interface p1 
bfd:min_tx=5000])
-# there will be poll sequences from both sides. and it is hard to determine the
-# order. so just skip 10000ms and check the RX/TX. at that time, p0 should be 
in decay already.
-for i in `seq 0 19`; do echo $i; ovs-appctl bfd/show; 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], [5000ms])
-BFD_CHECK_RX([p0], [5000ms], [3000ms], [500ms])
-# then, there should be no change of status,
-for i in `seq 0 9`
-do
-    ovs-appctl time/warp 500
-    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], [5000ms])
-    BFD_CHECK_RX([p0], [5000ms], [3000ms], [500ms])
-done
-# reset the p1's min_tx to 500ms.
-AT_CHECK([ovs-vsctl set Interface p1 bfd:min_tx=500])
-# check the poll sequence. since p0 has been in decay, now the RX will show 
3000ms.
-BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [final], [up], 
[No Diagnostic])
-BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [poll], [up], 
[No Diagnostic])
-BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
-BFD_CHECK_RX([p0], [3000ms], [3000ms], [500ms])
-# advance the clock by 3000ms, at that time, p1 will send the control packets.
-# then there will be no poll flags.
-for i in `seq 0 5`; 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])
-BFD_CHECK_RX([p0], [3000ms], [3000ms], [500ms])
-# End of Test-7 ###############################################################
-
-
-# Test-8 BFD decay: state up->down->up.
-# turn bfd off on p1
-AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=false])
-
-# check the state change of bfd on p0. After 9000 ms (3 min_rx intervals)
-for i in `seq 0 8`; do ovs-appctl time/warp 1000; done
-BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time 
Expired], [none], [down], [No Diagnostic])
-BFD_CHECK_TX([p0], [1000ms], [1000ms], [0ms])
-BFD_CHECK_RX([p0], [300ms], [300ms], [1ms])
-
-# resume the bfd on p1. the bfd should not go to decay mode direclty.
-AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=true])
-for i in `seq 0 1`; do ovs-appctl time/warp 500; done
-BFD_CHECK([p0], [true], [false], [none], [up], [Control Detection Time 
Expired], [none], [up], [No Diagnostic])
-BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
-BFD_CHECK_RX([p0], [500ms], [300ms], [500ms])
-
-# since the decay_min_rx is still 3000ms, so after 3000ms, there should be the 
decay and poll sequence.
-for i in `seq 0 5`; do ovs-appctl time/warp 500; done
-BFD_CHECK([p0], [true], [false], [none], [up], [Control Detection Time 
Expired], [final], [up], [No Diagnostic])
-BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [poll], [up], 
[Control Detection Time Expired])
-BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
-BFD_CHECK_RX([p0], [3000ms], [3000ms], [500ms])
-# End of Test-8 
################################################################
-
-OVS_VSWITCHD_STOP
-AT_CLEANUP
-
 # Tests below are for bfd forwarding_if_rx feature.
 # forwarding_if_rx Test1: bfd is enabled on one end of link.
 AT_SETUP([bfd - bfd forwarding_if_rx 1])
-- 
1.7.9.5

_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev

Reply via email to