#define STATS_INTERVAL (5 * 1000) /* In milliseconds. */
static long long int stats_timer = LLONG_MIN;
+/* Stores the time after which CFM statistics may be written to the database.
+ * Only updated when changes to the database require rate limiting. */
+#define CFM_LIMIT_INTERVAL (1 * 1000) /* In milliseconds. */
+static long long int cfm_limiter = LLONG_MIN;
+
static struct bridge *bridge_create(const struct ovsrec_bridge *br_cfg);
static void bridge_destroy(struct bridge *);
static struct bridge *bridge_lookup(const char *name);
static uint64_t dpid_from_hash(const void *, size_t nbytes);
static unixctl_cb_func bridge_unixctl_fdb_show;
+static unixctl_cb_func cfm_unixctl_show;
static unixctl_cb_func qos_unixctl_show;
static void bond_init(void);
static void iface_set_ofport(const struct ovsrec_interface *, int64_t ofport);
static void iface_update_qos(struct iface *, const struct ovsrec_qos *);
static void iface_update_cfm(struct iface *);
-static void iface_refresh_cfm_stats(struct iface *iface);
+static bool iface_refresh_cfm_stats(struct iface *iface);
static void iface_update_carrier(struct iface *);
static bool iface_get_carrier(const struct iface *);
/* Register unixctl commands. */
unixctl_command_register("fdb/show", bridge_unixctl_fdb_show, NULL);
+ unixctl_command_register("cfm/show", cfm_unixctl_show, NULL);
unixctl_command_register("qos/show", qos_unixctl_show, NULL);
unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows,
NULL);
}
}
-static void
+/* Writes 'iface''s CFM statistics to the database. Returns true if anything
+ * changed, false otherwise. */
+static bool
iface_refresh_cfm_stats(struct iface *iface)
{
const struct ovsrec_monitor *mon;
const struct cfm *cfm;
+ bool changed = false;
size_t i;
mon = iface->cfg->monitor;
cfm = ofproto_iface_get_cfm(iface->port->bridge->ofproto, iface->dp_ifidx);
if (!cfm || !mon) {
- return;
+ return false;
}
for (i = 0; i < mon->n_remote_mps; i++) {
mp = mon->remote_mps[i];
rmp = cfm_get_remote_mp(cfm, mp->mpid);
- ovsrec_maintenance_point_set_fault(mp, &rmp->fault, 1);
- }
-
- if (hmap_is_empty(&cfm->x_remote_mps)) {
- ovsrec_monitor_set_unexpected_remote_mpids(mon, NULL, 0);
- } else {
- size_t length;
- struct remote_mp *rmp;
- int64_t *x_remote_mps;
-
- length = hmap_count(&cfm->x_remote_mps);
- x_remote_mps = xzalloc(length * sizeof *x_remote_mps);
-
- i = 0;
- HMAP_FOR_EACH (rmp, node, &cfm->x_remote_mps) {
- x_remote_mps[i++] = rmp->mpid;
+ if (mp->n_fault != 1 || mp->fault[0] != rmp->fault) {
+ ovsrec_maintenance_point_set_fault(mp, &rmp->fault, 1);
+ changed = true;
}
-
- ovsrec_monitor_set_unexpected_remote_mpids(mon, x_remote_mps, length);
- free(x_remote_mps);
}
- if (hmap_is_empty(&cfm->x_remote_maids)) {
- ovsrec_monitor_set_unexpected_remote_maids(mon, NULL, 0);
- } else {
- size_t length;
- char **x_remote_maids;
- struct remote_maid *rmaid;
-
- length = hmap_count(&cfm->x_remote_maids);
- x_remote_maids = xzalloc(length * sizeof *x_remote_maids);
-
- i = 0;
- HMAP_FOR_EACH (rmaid, node, &cfm->x_remote_maids) {
- size_t j;
-
- x_remote_maids[i] = xzalloc(CCM_MAID_LEN * 2 + 1);
-
- for (j = 0; j < CCM_MAID_LEN; j++) {
- snprintf(&x_remote_maids[i][j * 2], 3, "%02hhx",
- rmaid->maid[j]);
- }
- i++;
- }
- ovsrec_monitor_set_unexpected_remote_maids(mon, x_remote_maids, length);
-
- for (i = 0; i < length; i++) {
- free(x_remote_maids[i]);
- }
- free(x_remote_maids);
+ if (mon->n_fault != 1 || mon->fault[0] != cfm->fault) {
+ ovsrec_monitor_set_fault(mon, &cfm->fault, 1);
+ changed = true;
}
- ovsrec_monitor_set_fault(mon, &cfm->fault, 1);
+ return changed;
}
static void
LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
iface_refresh_stats(iface);
- iface_refresh_cfm_stats(iface);
iface_refresh_status(iface);
}
}
stats_timer = time_msec() + STATS_INTERVAL;
}
+
+ if (time_msec() >= cfm_limiter) {
+ struct ovsdb_idl_txn *txn;
+ bool changed = false;
+
+ txn = ovsdb_idl_txn_create(idl);
+ LIST_FOR_EACH (br, node, &all_bridges) {
+ struct port *port;
+
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
+ struct iface *iface;
+
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
+ changed = iface_refresh_cfm_stats(iface) || changed;
+ }
+ }
+ }
+
+ if (changed) {
+ cfm_limiter = time_msec() + CFM_LIMIT_INTERVAL;
+ }
+
+ ovsdb_idl_txn_commit(txn);
+ ovsdb_idl_txn_destroy(txn);
+ }
}
void
struct port *port;
ofproto_wait(br->ofproto);
- if (ofproto_has_primary_controller(br->ofproto)) {
- continue;
- }
-
mac_learning_wait(br->ml);
-
HMAP_FOR_EACH (port, hmap_node, &br->ports) {
port_wait(port);
}
}
ovsdb_idl_wait(idl);
poll_timer_wait_until(stats_timer);
+
+ if (cfm_limiter > time_msec()) {
+ poll_timer_wait_until(cfm_limiter);
+ }
}
/* Forces 'br' to revalidate all of its flows. This is appropriate when 'br''s
ds_destroy(&ds);
}
\f
+/* CFM unixctl user interface functions. */
+static void
+cfm_unixctl_show(struct unixctl_conn *conn,
+ const char *args, void *aux OVS_UNUSED)
+{
+ struct ds ds = DS_EMPTY_INITIALIZER;
+ struct iface *iface;
+ const struct cfm *cfm;
+
+ iface = iface_find(args);
+ if (!iface) {
+ unixctl_command_reply(conn, 501, "no such interface");
+ return;
+ }
+
+ cfm = ofproto_iface_get_cfm(iface->port->bridge->ofproto, iface->dp_ifidx);
+
+ if (!cfm) {
+ unixctl_command_reply(conn, 501, "CFM not enabled");
+ return;
+ }
+
+ cfm_dump_ds(cfm, &ds);
+ unixctl_command_reply(conn, 200, ds_cstr(&ds));
+ ds_destroy(&ds);
+}
+\f
/* QoS unixctl user interface functions. */
struct qos_unixctl_show_cbdata {
struct cfm cfm;
uint16_t *remote_mps;
struct ovsrec_monitor *mon;
- uint8_t ea[ETH_ADDR_LEN], maid[CCM_MAID_LEN];
+ uint8_t maid[CCM_MAID_LEN];
mon = iface->cfg->monitor;
return;
}
- if (netdev_get_etheraddr(iface->netdev, ea)) {
- VLOG_WARN("interface %s: Failed to get ethernet address. "
- "Skipping Monitor.", iface->name);
- return;
- }
-
if (!cfm_generate_maid(mon->md_name, mon->ma_name, maid)) {
VLOG_WARN("interface %s: Failed to generate MAID.", iface->name);
return;
cfm.mpid = mon->mpid;
cfm.interval = mon->interval ? *mon->interval : 1000;
- memcpy(cfm.eth_src, ea, sizeof cfm.eth_src);
memcpy(cfm.maid, maid, sizeof cfm.maid);
remote_mps = xzalloc(mon->n_remote_mps * sizeof *remote_mps);