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 | 23 +++++++++++++++++++++++ lib/cfm.h | 2 ++ ofproto/ofproto-dpif.c | 14 ++++++++++++++ ofproto/ofproto-provider.h | 10 ++++++++++ ofproto/ofproto.c | 14 ++++++++++++++ ofproto/ofproto.h | 3 +++ vswitchd/bridge.c | 41 ++++++++++++++++++++++++++++++++++++++++- vswitchd/vswitch.ovsschema | 7 ++++++- 8 files changed, 112 insertions(+), 2 deletions(-) diff --git a/lib/cfm.c b/lib/cfm.c index 829b862..5d2615c 100644 --- a/lib/cfm.c +++ b/lib/cfm.c @@ -29,6 +29,7 @@ #include "ofpbuf.h" #include "packets.h" #include "poll-loop.h" +#include "sset.h" #include "timer.h" #include "timeval.h" #include "unixctl.h" @@ -508,6 +509,28 @@ cfm_get_fault(const struct cfm *cfm) return cfm->fault; } +/* Writes the MPIDs of the remote maintenance points reachable by 'cfm' to + * 'remote_mps'. No more than CFM_MAX_RMPS MPIDs will be written to + * 'remote_mps'. Clears 'remote_mps' before modifying it. */ +void +cfm_get_remote_mpids(const struct cfm *cfm, struct sset *remote_mps) +{ + struct remote_mp *rmp; + + sset_clear(remote_mps); + HMAP_FOR_EACH (rmp, node, &cfm->remote_mps) { + char *rmp_str; + + if (cfm->extended) { + rmp_str = xasprintf(ETH_ADDR_FMT, ETH_ADDR_ARGS(rmp->mpid.mpidx)); + } else { + rmp_str = xasprintf("%"PRIu16, rmp->mpid.mpid); + } + + sset_add_and_free(remote_mps, rmp_str); + } +} + static struct cfm * cfm_find(const char *name) { diff --git a/lib/cfm.h b/lib/cfm.h index c167258..acd8c41 100644 --- a/lib/cfm.h +++ b/lib/cfm.h @@ -25,6 +25,7 @@ struct flow; struct ofpbuf; +struct sset; struct cfm_settings { uint16_t mpid; /* The MPID of this CFM. */ @@ -45,5 +46,6 @@ 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 *, struct sset *remote_mps); #endif /* cfm.h */ diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index a8c3b16..1aa1db6 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -813,6 +813,19 @@ 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_, struct sset *rmps) +{ + struct ofport_dpif *ofport = ofport_dpif_cast(ofport_); + + if (ofport->cfm) { + cfm_get_remote_mpids(ofport->cfm, rmps); + return 0; + } else { + return -1; + } +} /* Bundles. */ @@ -4252,6 +4265,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, diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index 037dbae..02d2333 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -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" @@ -873,6 +874,15 @@ 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'. Writes its result to '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, + struct sset *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 diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 849a376..d55ad65 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -2003,6 +2003,20 @@ 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'. 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, + struct sset *rmps) +{ + struct ofport *ofport = ofproto_get_port(ofproto, ofp_port); + return (ofport && ofproto->ofproto_class->get_cfm_remote_mpids + ? ofproto->ofproto_class->get_cfm_remote_mpids(ofport, rmps) + : -1); +} + static int handle_aggregate_stats_request(struct ofconn *ofconn, const struct ofp_stats_msg *osm) diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h index e0c99ea..d0e4803 100644 --- a/ofproto/ofproto.h +++ b/ofproto/ofproto.h @@ -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,8 @@ 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, struct sset *rmps); void ofproto_get_ofproto_controller_info(const struct ofproto *, struct shash *); void ofproto_free_ofproto_controller_info(struct shash *); diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index fbcaa2e..413fce4 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -1261,7 +1261,10 @@ iface_refresh_cfm_stats(struct iface *iface) { const struct ovsrec_interface *cfg = iface->cfg; bool changed = false; - int fault; + + struct sset rmps = SSET_INITIALIZER(&rmps); + struct sset rmps_db = SSET_INITIALIZER(&rmps_db); + int fault, error; fault = ofproto_port_get_cfm_fault(iface->port->bridge->ofproto, iface->ofp_port); @@ -1269,12 +1272,43 @@ iface_refresh_cfm_stats(struct iface *iface) goto error; } + error = ofproto_port_get_cfm_remote_mpids(iface->port->bridge->ofproto, + iface->ofp_port, &rmps); + if (error) { + goto error; + } + if (cfg->n_cfm_fault != 1 || cfg->cfm_fault[0] != fault) { bool fault_bool = fault; ovsrec_interface_set_cfm_fault(cfg, &fault_bool, 1); changed = true; } + sset_add_array(&rmps_db, cfg->cfm_remote_mpids, + cfg->n_cfm_remote_mpids); + + if (!sset_equals(&rmps, &rmps_db)) { + char *rmps_array[CFM_MAX_RMPS]; + size_t n_rmps; + + n_rmps = sset_to_array(&rmps, rmps_array, CFM_MAX_RMPS); + + if (n_rmps < sset_count(&rmps)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + + /* XXX: Perhaps this information should be communicated in the + * database somehow. */ + VLOG_WARN_RL(&rl, "%s: too many remote_mpids to write", + iface->name); + } + + ovsrec_interface_set_cfm_remote_mpids(cfg, rmps_array, n_rmps); + changed = true; + } + + sset_destroy(&rmps); + sset_destroy(&rmps_db); + return changed; error: @@ -1284,6 +1318,11 @@ error: changed = true; } + if (cfg->n_cfm_remote_mpids) { + ovsrec_interface_set_cfm_remote_mpids(cfg, NULL, 0); + changed = true; + } + return changed; } diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema index 53cd1f0..5c550c0 100644 --- a/vswitchd/vswitch.ovsschema +++ b/vswitchd/vswitch.ovsschema @@ -1,6 +1,6 @@ {"name": "Open_vSwitch", "version": "6.0.0", - "cksum": "2055559034 14338", + "cksum": "1007312010 14478", "tables": { "Open_vSwitch": { "columns": { @@ -171,6 +171,11 @@ "key": {"type": "string"}, "min": 0, "max": 1}}, + "cfm_remote_mpids": { + "type": { + "key": {"type": "string"}, + "min": 0, + "max": "unlimited"}}, "cfm_fault": { "type": { "key": { "type": "boolean"}, -- 1.7.6.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev