+ ovsrec_interface_set_cfm_fault(cfg, NULL, 0);
+ ovsrec_interface_set_cfm_fault_status(cfg, NULL, 0);
+ }
+
+ opup = ofproto_port_get_cfm_opup(iface->port->bridge->ofproto,
+ iface->ofp_port);
+ if (opup >= 0) {
+ ovsrec_interface_set_cfm_remote_opstate(cfg, opup ? "up" : "down");
+ } else {
+ ovsrec_interface_set_cfm_remote_opstate(cfg, NULL);
+ }
+
+ 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);
+ }
+
+ health = ofproto_port_get_cfm_health(iface->port->bridge->ofproto,
+ iface->ofp_port);
+ if (health >= 0) {
+ int64_t cfm_health = health;
+ ovsrec_interface_set_cfm_health(cfg, &cfm_health, 1);
+ } else {
+ ovsrec_interface_set_cfm_health(cfg, NULL, 0);
+ }
+}
+
+static void
+iface_refresh_stats(struct iface *iface)
+{
+#define IFACE_STATS \
+ IFACE_STAT(rx_packets, "rx_packets") \
+ IFACE_STAT(tx_packets, "tx_packets") \
+ IFACE_STAT(rx_bytes, "rx_bytes") \
+ IFACE_STAT(tx_bytes, "tx_bytes") \
+ IFACE_STAT(rx_dropped, "rx_dropped") \
+ IFACE_STAT(tx_dropped, "tx_dropped") \
+ IFACE_STAT(rx_errors, "rx_errors") \
+ IFACE_STAT(tx_errors, "tx_errors") \
+ IFACE_STAT(rx_frame_errors, "rx_frame_err") \
+ IFACE_STAT(rx_over_errors, "rx_over_err") \
+ IFACE_STAT(rx_crc_errors, "rx_crc_err") \
+ IFACE_STAT(collisions, "collisions")
+
+#define IFACE_STAT(MEMBER, NAME) NAME,
+ static char *keys[] = { IFACE_STATS };
+#undef IFACE_STAT
+ int64_t values[ARRAY_SIZE(keys)];
+ int i;
+
+ struct netdev_stats stats;
+
+ if (iface_is_synthetic(iface)) {
+ return;
+ }
+
+ /* Intentionally ignore return value, since errors will set 'stats' to
+ * all-1s, and we will deal with that correctly below. */
+ netdev_get_stats(iface->netdev, &stats);
+
+ /* Copy statistics into values[] array. */
+ i = 0;
+#define IFACE_STAT(MEMBER, NAME) values[i++] = stats.MEMBER;
+ IFACE_STATS;
+#undef IFACE_STAT
+ assert(i == ARRAY_SIZE(keys));
+
+ ovsrec_interface_set_statistics(iface->cfg, keys, values,
+ ARRAY_SIZE(keys));
+#undef IFACE_STATS
+}
+
+static void
+br_refresh_stp_status(struct bridge *br)
+{
+ struct smap smap = SMAP_INITIALIZER(&smap);
+ struct ofproto *ofproto = br->ofproto;
+ struct ofproto_stp_status status;
+
+ if (ofproto_get_stp_status(ofproto, &status)) {
+ return;
+ }
+
+ if (!status.enabled) {
+ ovsrec_bridge_set_status(br->cfg, NULL);
+ return;
+ }
+
+ smap_add_format(&smap, "stp_bridge_id", STP_ID_FMT,
+ STP_ID_ARGS(status.bridge_id));
+ smap_add_format(&smap, "stp_designated_root", STP_ID_FMT,
+ STP_ID_ARGS(status.designated_root));
+ smap_add_format(&smap, "stp_root_path_cost", "%d", status.root_path_cost);
+
+ ovsrec_bridge_set_status(br->cfg, &smap);
+ smap_destroy(&smap);
+}
+
+static void
+port_refresh_stp_status(struct port *port)
+{
+ struct ofproto *ofproto = port->bridge->ofproto;
+ struct iface *iface;
+ struct ofproto_port_stp_status status;
+ char *keys[3];
+ int64_t int_values[3];
+ struct smap smap;
+
+ if (port_is_synthetic(port)) {
+ return;
+ }
+
+ /* STP doesn't currently support bonds. */
+ if (!list_is_singleton(&port->ifaces)) {
+ ovsrec_port_set_status(port->cfg, NULL);
+ return;
+ }
+
+ iface = CONTAINER_OF(list_front(&port->ifaces), struct iface, port_elem);
+
+ if (ofproto_port_get_stp_status(ofproto, iface->ofp_port, &status)) {
+ return;
+ }
+
+ if (!status.enabled) {
+ ovsrec_port_set_status(port->cfg, NULL);
+ ovsrec_port_set_statistics(port->cfg, NULL, NULL, 0);
+ return;
+ }
+
+ /* Set Status column. */
+ smap_init(&smap);
+ smap_add_format(&smap, "stp_port_id", STP_PORT_ID_FMT, status.port_id);
+ smap_add(&smap, "stp_state", stp_state_name(status.state));
+ smap_add_format(&smap, "stp_sec_in_state", "%u", status.sec_in_state);
+ smap_add(&smap, "stp_role", stp_role_name(status.role));
+ ovsrec_port_set_status(port->cfg, &smap);
+ smap_destroy(&smap);
+
+ /* Set Statistics column. */
+ keys[0] = "stp_tx_count";
+ int_values[0] = status.tx_count;
+ keys[1] = "stp_rx_count";
+ int_values[1] = status.rx_count;
+ keys[2] = "stp_error_count";
+ int_values[2] = status.error_count;
+
+ ovsrec_port_set_statistics(port->cfg, keys, int_values,
+ ARRAY_SIZE(int_values));
+}
+
+static bool
+enable_system_stats(const struct ovsrec_open_vswitch *cfg)
+{
+ return smap_get_bool(&cfg->other_config, "enable-statistics", false);
+}
+
+static void
+reconfigure_system_stats(const struct ovsrec_open_vswitch *cfg)
+{
+ bool enable = enable_system_stats(cfg);
+
+ system_stats_enable(enable);
+ if (!enable) {
+ ovsrec_open_vswitch_set_statistics(cfg, NULL);
+ }
+}
+
+static void
+run_system_stats(void)
+{
+ const struct ovsrec_open_vswitch *cfg = ovsrec_open_vswitch_first(idl);
+ struct smap *stats;
+
+ stats = system_stats_run();
+ if (stats && cfg) {
+ struct ovsdb_idl_txn *txn;
+ struct ovsdb_datum datum;
+
+ txn = ovsdb_idl_txn_create(idl);
+ ovsdb_datum_from_smap(&datum, stats);
+ ovsdb_idl_txn_write(&cfg->header_, &ovsrec_open_vswitch_col_statistics,
+ &datum);
+ ovsdb_idl_txn_commit(txn);
+ ovsdb_idl_txn_destroy(txn);
+
+ free(stats);
+ }
+}
+
+static inline const char *
+nx_role_to_str(enum nx_role role)
+{
+ switch (role) {
+ case NX_ROLE_OTHER:
+ return "other";
+ case NX_ROLE_MASTER:
+ return "master";
+ case NX_ROLE_SLAVE:
+ return "slave";
+ default:
+ return "*** INVALID ROLE ***";
+ }
+}
+
+static void
+refresh_controller_status(void)
+{
+ struct bridge *br;
+ struct shash info;
+ const struct ovsrec_controller *cfg;
+
+ shash_init(&info);
+
+ /* Accumulate status for controllers on all bridges. */
+ HMAP_FOR_EACH (br, node, &all_bridges) {
+ ofproto_get_ofproto_controller_info(br->ofproto, &info);
+ }
+
+ /* Update each controller in the database with current status. */
+ OVSREC_CONTROLLER_FOR_EACH(cfg, idl) {
+ struct ofproto_controller_info *cinfo =
+ shash_find_data(&info, cfg->target);
+
+ if (cinfo) {
+ struct smap smap = SMAP_INITIALIZER(&smap);
+ const char **values = cinfo->pairs.values;
+ const char **keys = cinfo->pairs.keys;
+ size_t i;
+
+ for (i = 0; i < cinfo->pairs.n; i++) {
+ smap_add(&smap, keys[i], values[i]);
+ }
+
+ ovsrec_controller_set_is_connected(cfg, cinfo->is_connected);
+ ovsrec_controller_set_role(cfg, nx_role_to_str(cinfo->role));
+ ovsrec_controller_set_status(cfg, &smap);
+ smap_destroy(&smap);
+ } else {
+ ovsrec_controller_set_is_connected(cfg, false);
+ ovsrec_controller_set_role(cfg, NULL);
+ ovsrec_controller_set_status(cfg, NULL);