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
hmap_destroy(&cfm->remote_mps);
hmap_remove(&all_cfms, &cfm->hmap_node);
+ free(cfm->rmps_array);
free(cfm->name);
free(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) {
rmp->mpid);
cfm->fault = true;
}
+
+ cfm->rmps_array[cfm->rmps_array_len++] = rmp->mpid;
}
}
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)
{
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 */
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. */
set_sflow,
set_cfm,
get_cfm_fault,
+ get_cfm_remote_mpids,
bundle_set,
bundle_remove,
mirror_set,
/* Definitions for use within ofproto. */
#include "ofproto/ofproto.h"
+#include "cfm.h"
#include "classifier.h"
#include "list.h"
#include "shash.h"
* 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
: -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)
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
+#include "cfm.h"
#include "flow.h"
#include "netflow.h"
#include "sset.h"
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 *);
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);
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);
} 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
{"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"},