cfm: Write remote MPIDs to the database.
authorEthan Jackson <ethan@nicira.com>
Fri, 26 Aug 2011 21:54:34 +0000 (14:54 -0700)
committerEthan Jackson <ethan@nicira.com>
Fri, 9 Sep 2011 21:11:14 +0000 (14:11 -0700)
A controller may want to know which MPIDs are reachable from an
interface configured with CFM.  This patch regularly writes this
information to the database.

Bug #7014.

lib/cfm.c
lib/cfm.h
ofproto/ofproto-dpif.c
ofproto/ofproto-provider.h
ofproto/ofproto.c
ofproto/ofproto.h
vswitchd/bridge.c
vswitchd/vswitch.ovsschema

index 245ce44..bc59b62 100644 (file)
--- a/lib/cfm.c
+++ b/lib/cfm.c
@@ -88,6 +88,11 @@ struct cfm {
     struct timer fault_timer; /* Check for faults when expired. */
 
     struct hmap remote_mps;   /* Remote MPs. */
+
+    /* Result of cfm_get_remote_mpids(). Updated only during fault check to
+     * avoid flapping. */
+    uint64_t *rmps_array;     /* Cache of remote_mps. */
+    size_t rmps_array_len;    /* Number of rmps in 'rmps_array'. */
 };
 
 /* Remote MPs represent foreign network entities that are configured to have
@@ -249,6 +254,7 @@ cfm_destroy(struct cfm *cfm)
 
     hmap_destroy(&cfm->remote_mps);
     hmap_remove(&all_cfms, &cfm->hmap_node);
+    free(cfm->rmps_array);
     free(cfm->name);
     free(cfm);
 }
@@ -264,6 +270,11 @@ cfm_run(struct cfm *cfm)
         cfm->fault = cfm->unexpected_recv;
         cfm->unexpected_recv = false;
 
+        cfm->rmps_array_len = 0;
+        free(cfm->rmps_array);
+        cfm->rmps_array = xmalloc(hmap_count(&cfm->remote_mps) *
+                                  sizeof *cfm->rmps_array);
+
         HMAP_FOR_EACH_SAFE (rmp, rmp_next, node, &cfm->remote_mps) {
 
             if (!rmp->recv) {
@@ -285,6 +296,8 @@ cfm_run(struct cfm *cfm)
                              rmp->mpid);
                     cfm->fault = true;
                 }
+
+                cfm->rmps_array[cfm->rmps_array_len++] = rmp->mpid;
             }
         }
 
@@ -480,6 +493,17 @@ cfm_get_fault(const struct cfm *cfm)
     return cfm->fault;
 }
 
+/* Populates 'rmps' with an array of remote maintenance points reachable by
+ * 'cfm'. The number of remote maintenance points is written to 'n_rmps'.
+ * 'cfm' retains ownership of the array written to 'rmps' */
+void
+cfm_get_remote_mpids(const struct cfm *cfm, const uint64_t **rmps,
+                     size_t *n_rmps)
+{
+    *rmps = cfm->rmps_array;
+    *n_rmps = cfm->rmps_array_len;
+}
+
 static struct cfm *
 cfm_find(const char *name)
 {
index 86d62d7..a031ab2 100644 (file)
--- a/lib/cfm.h
+++ b/lib/cfm.h
@@ -41,5 +41,7 @@ bool cfm_configure(struct cfm *, const struct cfm_settings *);
 bool cfm_should_process_flow(const struct cfm *cfm, const struct flow *);
 void cfm_process_heartbeat(struct cfm *, const struct ofpbuf *packet);
 bool cfm_get_fault(const struct cfm *);
+void cfm_get_remote_mpids(const struct cfm *, const uint64_t **rmps,
+                          size_t *n_rmps);
 
 #endif /* cfm.h */
index 9a71321..5d93153 100644 (file)
@@ -813,6 +813,20 @@ get_cfm_fault(const struct ofport *ofport_)
 
     return ofport->cfm ? cfm_get_fault(ofport->cfm) : -1;
 }
+
+static int
+get_cfm_remote_mpids(const struct ofport *ofport_, const uint64_t **rmps,
+                     size_t *n_rmps)
+{
+    struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
+
+    if (ofport->cfm) {
+        cfm_get_remote_mpids(ofport->cfm, rmps, n_rmps);
+        return 0;
+    } else {
+        return -1;
+    }
+}
 \f
 /* Bundles. */
 
@@ -4252,6 +4266,7 @@ const struct ofproto_class ofproto_dpif_class = {
     set_sflow,
     set_cfm,
     get_cfm_fault,
+    get_cfm_remote_mpids,
     bundle_set,
     bundle_remove,
     mirror_set,
index 8284418..fa583f8 100644 (file)
@@ -20,6 +20,7 @@
 /* Definitions for use within ofproto. */
 
 #include "ofproto/ofproto.h"
+#include "cfm.h"
 #include "classifier.h"
 #include "list.h"
 #include "shash.h"
@@ -878,6 +879,16 @@ struct ofproto_class {
      * not support CFM. */
     int (*get_cfm_fault)(const struct ofport *ofport);
 
+    /* Gets the MPIDs of the remote maintenance points broadcasting to
+     * 'ofport'.  Populates 'rmps' with a provider owned array of MPIDs, and
+     * 'n_rmps' with the number of MPIDs in 'rmps'. Returns a number less than
+     * 0 if CFM is not enabled of 'ofport'.
+     *
+     * This function may be a null pointer if the ofproto implementation does
+     * not support CFM. */
+    int (*get_cfm_remote_mpids)(const struct ofport *ofport,
+                                const uint64_t **rmps, size_t *n_rmps);
+
     /* If 's' is nonnull, this function registers a "bundle" associated with
      * client data pointer 'aux' in 'ofproto'.  A bundle is the same concept as
      * a Port in OVSDB, that is, it consists of one or more "slave" devices
index 15bcd13..cbd8928 100644 (file)
@@ -2003,6 +2003,25 @@ ofproto_port_get_cfm_fault(const struct ofproto *ofproto, uint16_t ofp_port)
             : -1);
 }
 
+/* Gets the MPIDs of the remote maintenance points broadcasting to 'ofp_port'
+ * within 'ofproto'.  Populates 'rmps' with an array of MPIDs owned by
+ * 'ofproto', and 'n_rmps' with the number of MPIDs in 'rmps'.  Returns a
+ * number less than 0 if CFM is not enabled on 'ofp_port'. */
+int
+ofproto_port_get_cfm_remote_mpids(const struct ofproto *ofproto,
+                                  uint16_t ofp_port, const uint64_t **rmps,
+                                  size_t *n_rmps)
+{
+    struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
+
+    *rmps = NULL;
+    *n_rmps = 0;
+    return (ofport && ofproto->ofproto_class->get_cfm_remote_mpids
+            ? ofproto->ofproto_class->get_cfm_remote_mpids(ofport, rmps,
+                                                           n_rmps)
+            : -1);
+}
+
 static int
 handle_aggregate_stats_request(struct ofconn *ofconn,
                                const struct ofp_stats_msg *osm)
index e0c99ea..3552aac 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
+#include "cfm.h"
 #include "flow.h"
 #include "netflow.h"
 #include "sset.h"
@@ -235,6 +236,9 @@ void ofproto_get_all_flows(struct ofproto *p, struct ds *);
 void ofproto_get_netflow_ids(const struct ofproto *,
                              uint8_t *engine_type, uint8_t *engine_id);
 int ofproto_port_get_cfm_fault(const struct ofproto *, uint16_t ofp_port);
+int ofproto_port_get_cfm_remote_mpids(const struct ofproto *,
+                                      uint16_t ofp_port, const uint64_t **rmps,
+                                      size_t *n_rmps);
 
 void ofproto_get_ofproto_controller_info(const struct ofproto *, struct shash *);
 void ofproto_free_ofproto_controller_info(struct shash *);
index 44b5fbe..abea4f3 100644 (file)
@@ -243,6 +243,7 @@ bridge_init(const char *remote)
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_statistics);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_status);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_fault);
+    ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_remote_mpids);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_lacp_current);
     ovsdb_idl_omit(idl, &ovsrec_interface_col_external_ids);
 
@@ -1262,7 +1263,9 @@ static void
 iface_refresh_cfm_stats(struct iface *iface)
 {
     const struct ovsrec_interface *cfg = iface->cfg;
-    int fault;
+    int fault, error;
+    const uint64_t *rmps;
+    size_t n_rmps;
 
     fault = ofproto_port_get_cfm_fault(iface->port->bridge->ofproto,
                                        iface->ofp_port);
@@ -1272,6 +1275,15 @@ iface_refresh_cfm_stats(struct iface *iface)
     } else {
         ovsrec_interface_set_cfm_fault(cfg, NULL, 0);
     }
+
+    error = ofproto_port_get_cfm_remote_mpids(iface->port->bridge->ofproto,
+                                              iface->ofp_port, &rmps, &n_rmps);
+    if (error >= 0) {
+        ovsrec_interface_set_cfm_remote_mpids(cfg, (const int64_t *)rmps,
+                                              n_rmps);
+    } else {
+        ovsrec_interface_set_cfm_remote_mpids(cfg, NULL, 0);
+    }
 }
 
 static bool
index 4a009b0..25047b5 100644 (file)
@@ -1,6 +1,6 @@
 {"name": "Open_vSwitch",
  "version": "6.0.0",
- "cksum": "277444055 14339",
+ "cksum": "3439303729 14480",
  "tables": {
    "Open_vSwitch": {
      "columns": {
            "key": {"type": "integer"},
            "min": 0,
            "max": 1}},
+       "cfm_remote_mpids": {
+         "type": {
+           "key": {"type": "integer"},
+           "min": 0,
+           "max": "unlimited"}},
        "cfm_fault": {
          "type": {
            "key": { "type": "boolean"},