bridge: Refresh STP statistics separately from status
[sliver-openvswitch.git] / vswitchd / bridge.c
index ec3633c..2b11c5b 100644 (file)
@@ -21,7 +21,6 @@
 #include "async-append.h"
 #include "bfd.h"
 #include "bitmap.h"
-#include "bond.h"
 #include "cfm.h"
 #include "coverage.h"
 #include "daemon.h"
@@ -39,6 +38,7 @@
 #include "ofp-print.h"
 #include "ofp-util.h"
 #include "ofpbuf.h"
+#include "ofproto/bond.h"
 #include "ofproto/ofproto.h"
 #include "poll-loop.h"
 #include "sha1.h"
@@ -376,6 +376,7 @@ bridge_init(const char *remote)
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_fault);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_fault_status);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_remote_mpids);
+    ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_flap_count);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_health);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_remote_opstate);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_bfd_status);
@@ -983,28 +984,44 @@ bridge_configure_sflow(struct bridge *br, int *sflow_bridge_number)
     sset_destroy(&oso.targets);
 }
 
+/* Returns whether a IPFIX row is valid. */
+static bool
+ovsrec_ipfix_is_valid(const struct ovsrec_ipfix *ipfix)
+{
+    return ipfix && ipfix->n_targets > 0;
+}
+
+/* Returns whether a Flow_Sample_Collector_Set row is valid. */
+static bool
+ovsrec_fscs_is_valid(const struct ovsrec_flow_sample_collector_set *fscs,
+                     const struct bridge *br)
+{
+    return ovsrec_ipfix_is_valid(fscs->ipfix) && fscs->bridge == br->cfg;
+}
+
 /* Set IPFIX configuration on 'br'. */
 static void
 bridge_configure_ipfix(struct bridge *br)
 {
     const struct ovsrec_ipfix *be_cfg = br->cfg->ipfix;
+    bool valid_be_cfg = ovsrec_ipfix_is_valid(be_cfg);
     const struct ovsrec_flow_sample_collector_set *fe_cfg;
     struct ofproto_ipfix_bridge_exporter_options be_opts;
     struct ofproto_ipfix_flow_exporter_options *fe_opts = NULL;
     size_t n_fe_opts = 0;
 
     OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH(fe_cfg, idl) {
-        if (fe_cfg->bridge == br->cfg) {
+        if (ovsrec_fscs_is_valid(fe_cfg, br)) {
             n_fe_opts++;
         }
     }
 
-    if (!be_cfg && n_fe_opts == 0) {
+    if (!valid_be_cfg && n_fe_opts == 0) {
         ofproto_set_ipfix(br->ofproto, NULL, NULL, 0);
         return;
     }
 
-    if (be_cfg) {
+    if (valid_be_cfg) {
         memset(&be_opts, 0, sizeof be_opts);
 
         sset_init(&be_opts.targets);
@@ -1034,7 +1051,7 @@ bridge_configure_ipfix(struct bridge *br)
         fe_opts = xcalloc(n_fe_opts, sizeof *fe_opts);
         opts = fe_opts;
         OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH(fe_cfg, idl) {
-            if (fe_cfg->bridge == br->cfg) {
+            if (ovsrec_fscs_is_valid(fe_cfg, br)) {
                 opts->collector_set_id = fe_cfg->id;
                 sset_init(&opts->targets);
                 sset_add_array(&opts->targets, fe_cfg->ipfix->targets,
@@ -1048,10 +1065,10 @@ bridge_configure_ipfix(struct bridge *br)
         }
     }
 
-    ofproto_set_ipfix(br->ofproto, be_cfg ? &be_opts : NULL, fe_opts,
+    ofproto_set_ipfix(br->ofproto, valid_be_cfg ? &be_opts : NULL, fe_opts,
                       n_fe_opts);
 
-    if (be_cfg) {
+    if (valid_be_cfg) {
         sset_destroy(&be_opts.targets);
     }
 
@@ -1890,11 +1907,13 @@ iface_refresh_cfm_stats(struct iface *iface)
         ovsrec_interface_set_cfm_fault(cfg, NULL, 0);
         ovsrec_interface_set_cfm_fault_status(cfg, NULL, 0);
         ovsrec_interface_set_cfm_remote_opstate(cfg, NULL);
+        ovsrec_interface_set_cfm_flap_count(cfg, NULL, 0);
         ovsrec_interface_set_cfm_health(cfg, NULL, 0);
         ovsrec_interface_set_cfm_remote_mpids(cfg, NULL, 0);
     } else {
         const char *reasons[CFM_FAULT_N_REASONS];
         int64_t cfm_health = status.health;
+        int64_t cfm_flap_count = status.flap_count;
         bool faulted = status.faults != 0;
         size_t i, j;
 
@@ -1909,6 +1928,8 @@ iface_refresh_cfm_stats(struct iface *iface)
         }
         ovsrec_interface_set_cfm_fault_status(cfg, (char **) reasons, j);
 
+        ovsrec_interface_set_cfm_flap_count(cfg, &cfm_flap_count, 1);
+
         if (status.remote_opstate >= 0) {
             const char *remote_opstate = status.remote_opstate ? "up" : "down";
             ovsrec_interface_set_cfm_remote_opstate(cfg, remote_opstate);
@@ -2011,8 +2032,6 @@ 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)) {
@@ -2026,14 +2045,12 @@ port_refresh_stp_status(struct port *port)
     }
 
     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;
     }
 
@@ -2045,14 +2062,43 @@ port_refresh_stp_status(struct port *port)
     smap_add(&smap, "stp_role", stp_role_name(status.role));
     ovsrec_port_set_status(port->cfg, &smap);
     smap_destroy(&smap);
+}
+
+static void
+port_refresh_stp_stats(struct port *port)
+{
+    struct ofproto *ofproto = port->bridge->ofproto;
+    struct iface *iface;
+    struct ofproto_port_stp_stats stats;
+    char *keys[3];
+    int64_t int_values[3];
+
+    if (port_is_synthetic(port)) {
+        return;
+    }
+
+    /* STP doesn't currently support bonds. */
+    if (!list_is_singleton(&port->ifaces)) {
+        return;
+    }
+
+    iface = CONTAINER_OF(list_front(&port->ifaces), struct iface, port_elem);
+    if (ofproto_port_get_stp_stats(ofproto, iface->ofp_port, &stats)) {
+        return;
+    }
+
+    if (!stats.enabled) {
+        ovsrec_port_set_statistics(port->cfg, NULL, NULL, 0);
+        return;
+    }
 
     /* Set Statistics column. */
     keys[0] = "stp_tx_count";
-    int_values[0] = status.tx_count;
+    int_values[0] = stats.tx_count;
     keys[1] = "stp_rx_count";
-    int_values[1] = status.rx_count;
+    int_values[1] = stats.rx_count;
     keys[2] = "stp_error_count";
-    int_values[2] = status.error_count;
+    int_values[2] = stats.error_count;
 
     ovsrec_port_set_statistics(port->cfg, keys, int_values,
                                ARRAY_SIZE(int_values));
@@ -2478,6 +2524,8 @@ bridge_run(void)
                         iface_refresh_stats(iface);
                         iface_refresh_status(iface);
                     }
+
+                    port_refresh_stp_stats(port);
                 }
 
                 HMAP_FOR_EACH (m, hmap_node, &br->mirrors) {
@@ -3297,8 +3345,8 @@ port_configure_lacp(struct port *port, struct lacp_settings *s)
 
     system_id = smap_get(&port->cfg->other_config, "lacp-system-id");
     if (system_id) {
-        if (sscanf(system_id, ETH_ADDR_SCAN_FMT,
-                   ETH_ADDR_SCAN_ARGS(s->id)) != ETH_ADDR_SCAN_COUNT) {
+        if (!ovs_scan(system_id, ETH_ADDR_SCAN_FMT,
+                      ETH_ADDR_SCAN_ARGS(s->id))) {
             VLOG_WARN("port %s: LACP system ID (%s) must be an Ethernet"
                       " address.", port->name, system_id);
             return NULL;
@@ -3321,6 +3369,10 @@ port_configure_lacp(struct port *port, struct lacp_settings *s)
 
     lacp_time = smap_get(&port->cfg->other_config, "lacp-time");
     s->fast = lacp_time && !strcasecmp(lacp_time, "fast");
+
+    s->fallback_ab_cfg = smap_get_bool(&port->cfg->other_config,
+                                       "lacp-fallback-ab", false);
+
     return s;
 }
 
@@ -3409,6 +3461,9 @@ port_configure_bond(struct port *port, struct bond_settings *s)
 
     s->fake_iface = port->cfg->bond_fake_iface;
 
+    s->lacp_fallback_ab_cfg = smap_get_bool(&port->cfg->other_config,
+                                       "lacp-fallback-ab", false);
+
     LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
         netdev_set_miimon_interval(iface->netdev, miimon_interval);
     }
@@ -3566,10 +3621,9 @@ iface_set_mac(struct iface *iface)
 static void
 iface_set_ofport(const struct ovsrec_interface *if_cfg, ofp_port_t ofport)
 {
-    int64_t port_;
-    port_ = (ofport == OFPP_NONE) ? -1 : ofp_to_u16(ofport);
     if (if_cfg && !ovsdb_idl_row_is_synthetic(&if_cfg->header_)) {
-        ovsrec_interface_set_ofport(if_cfg, &port_, 1);
+        int64_t port = ofport == OFPP_NONE ? -1 : ofp_to_u16(ofport);
+        ovsrec_interface_set_ofport(if_cfg, &port, 1);
     }
 }