bridge: Implement basic periodic update of interface statistics.
authorBen Pfaff <blp@nicira.com>
Wed, 23 Jun 2010 18:02:46 +0000 (11:02 -0700)
committerBen Pfaff <blp@nicira.com>
Wed, 23 Jun 2010 19:43:03 +0000 (12:43 -0700)
vswitchd/bridge.c
vswitchd/vswitch.ovsschema
vswitchd/vswitch.xml

index e4e582ca7ec99a9f3ced688db8c7a2d2e200803c..3768eb9c625657d858f1c2bad83c502f5fb67483 100644 (file)
@@ -186,6 +186,11 @@ static struct list all_bridges = LIST_INITIALIZER(&all_bridges);
 /* OVSDB IDL used to obtain configuration. */
 static struct ovsdb_idl *idl;
 
+/* Each time this timer expires, the bridge fetches statistics for every
+ * interface and pushes them into the database. */
+#define IFACE_STATS_INTERVAL (5 * 1000) /* In milliseconds. */
+static long long int iface_stats_timer = 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);
@@ -286,6 +291,8 @@ bridge_configure_once(const struct ovsrec_open_vswitch *cfg)
     }
     already_configured_once = true;
 
+    iface_stats_timer = time_msec() + IFACE_STATS_INTERVAL;
+
     /* Get all the configured bridges' names from 'cfg' into 'bridge_names'. */
     svec_init(&bridge_names);
     for (i = 0; i < cfg->n_bridges; i++) {
@@ -1049,6 +1056,53 @@ dpid_from_hash(const void *data, size_t n)
     return eth_addr_to_uint64(hash);
 }
 
+static void
+iface_refresh_stats(struct iface *iface)
+{
+    struct iface_stat {
+        char *name;
+        int offset;
+    };
+    static const struct iface_stat iface_stats[] = {
+        { "rx_packets", offsetof(struct netdev_stats, rx_packets) },
+        { "tx_packets", offsetof(struct netdev_stats, tx_packets) },
+        { "rx_bytes", offsetof(struct netdev_stats, rx_bytes) },
+        { "tx_bytes", offsetof(struct netdev_stats, tx_bytes) },
+        { "rx_dropped", offsetof(struct netdev_stats, rx_dropped) },
+        { "tx_dropped", offsetof(struct netdev_stats, tx_dropped) },
+        { "rx_errors", offsetof(struct netdev_stats, rx_errors) },
+        { "tx_errors", offsetof(struct netdev_stats, tx_errors) },
+        { "rx_frame_err", offsetof(struct netdev_stats, rx_frame_errors) },
+        { "rx_over_err", offsetof(struct netdev_stats, rx_over_errors) },
+        { "rx_crc_err", offsetof(struct netdev_stats, rx_crc_errors) },
+        { "collisions", offsetof(struct netdev_stats, collisions) },
+    };
+    enum { N_STATS = ARRAY_SIZE(iface_stats) };
+    const struct iface_stat *s;
+
+    char *keys[N_STATS];
+    int64_t values[N_STATS];
+    int n;
+
+    struct netdev_stats stats;
+
+    /* 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);
+
+    n = 0;
+    for (s = iface_stats; s < &iface_stats[N_STATS]; s++) {
+        uint64_t value = *(uint64_t *) (((char *) &stats) + s->offset);
+        if (value != UINT64_MAX) {
+            keys[n] = s->name;
+            values[n] = value;
+            n++;
+        }
+    }
+
+    ovsrec_interface_set_statistics(iface->cfg, keys, values, n);
+}
+
 void
 bridge_run(void)
 {
@@ -1087,6 +1141,30 @@ bridge_run(void)
             bridge_reconfigure(&null_cfg);
         }
     }
+
+    /* Refresh interface stats if necessary. */
+    if (time_msec() >= iface_stats_timer) {
+        struct ovsdb_idl_txn *txn;
+
+        txn = ovsdb_idl_txn_create(idl);
+        LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
+            size_t i;
+
+            for (i = 0; i < br->n_ports; i++) {
+                struct port *port = br->ports[i];
+                size_t j;
+
+                for (j = 0; j < port->n_ifaces; j++) {
+                    struct iface *iface = port->ifaces[j];
+                    iface_refresh_stats(iface);
+                }
+            }
+        }
+        ovsdb_idl_txn_commit(txn);
+        ovsdb_idl_txn_destroy(txn); /* XXX */
+
+        iface_stats_timer = time_msec() + IFACE_STATS_INTERVAL;
+    }
 }
 
 void
@@ -1104,6 +1182,7 @@ bridge_wait(void)
         bond_wait(br);
     }
     ovsdb_idl_wait(idl);
+    poll_timer_wait_until(iface_stats_timer);
 }
 
 /* Forces 'br' to revalidate all of its flows.  This is appropriate when 'br''s
index 8b6fb8ba6d5f687a025e56e3e66947a970444c8b..b38463b0f11d22ee06656339b920581223465aaa 100644 (file)
          "type": {"key": "string",
                   "value": {"type": "uuid",
                             "refTable": "Capability"},
-                  "min": 0, "max": "unlimited"}}},
+                  "min": 0, "max": "unlimited"}},
+       "statistics": {
+         "type": {"key": "string", "value": "integer", "min": 0, "max": "unlimited"},
+         "ephemeral": true}},
      "maxRows": 1},
    "Capability": {
      "columns": {
          "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
        "ofport": {
          "type": {"key": "integer", "min": 0, "max": 1},
+         "ephemeral": true},
+       "statistics": {
+         "type": {"key": "string", "value": "integer", "min": 0, "max": "unlimited"},
          "ephemeral": true}}},
    "QoS": {
      "columns": {
index 0a3a6c237c22051982ba3a3d70333fb6d436cbe1..b93a8db2068686fa0a810cba0b13105b7719d6c8 100644 (file)
         capability categories and the meaning of associated
         <ref table="Capability"/> records.
       </column>
+
+      <column name="statistics">
+        <p>
+          Key-value pairs that report statistics about a running Open_vSwitch
+          daemon.  The current implementation updates these counters
+          periodically.  In the future, we plan to, instead, update them only
+          when they are queried (e.g. using an OVSDB <code>select</code>
+          operation) and perhaps at other times, but not on any regular
+          periodic basis.</p>
+        <p>
+          The currently defined key-value pairs are listed below.  Some Open
+          vSwitch implementations may not support some statistics, in which
+          case those key-value pairs are omitted.</p>
+        <dl>
+          <dt><code>load-average</code></dt>
+          <dd>
+            System load average multiplied by 100 and rounded to the nearest
+            integer.</dd>
+        </dl>
+      </column>
     </group>
   </table>
 
               field in the VIF record for this interface.</dd>
         </dl>
       </column>
+
+      <column name="statistics">
+        <p>
+          Key-value pairs that report interface statistics.  The current
+          implementation updates these counters periodically.  In the future,
+          we plan to, instead, update them when an interface is created, when
+          they are queried (e.g. using an OVSDB <code>select</code> operation),
+          and just before an interface is deleted due to virtual interface
+          hot-unplug or VM shutdown, and perhaps at other times, but not on any
+          regular periodic basis.</p>
+        <p>
+          The currently defined key-value pairs are listed below.  These are
+          the same statistics reported by OpenFlow in its <code>struct
+          ofp_port_stats</code> structure.  If an interface does not support a
+          given statistic, then that pair is omitted.</p>
+        <ul>
+          <li>
+            Successful transmit and receive counters:
+            <dl>
+              <dt><code>rx_packets</code></dt>
+              <dd>Number of received packets.</dd>
+              <dt><code>rx_bytes</code></dt>
+              <dd>Number of received bytes.</dd>
+              <dt><code>tx_packets</code></dt>
+              <dd>Number of transmitted packets.</dd>
+              <dt><code>tx_bytes</code></dt>
+              <dd>Number of transmitted bytes.</dd>
+            </dl>
+          </li>
+          <li>
+            Receive errors:
+            <dl>
+              <dt><code>rx_dropped</code></dt>
+              <dd>Number of packets dropped by RX.</dd>
+              <dt><code>rx_frame_err</code></dt>
+              <dd>Number of frame alignment errors.</dd>
+              <dt><code>rx_over_err</code></dt>
+              <dd>Number of packets with RX overrun.</dd>
+              <dt><code>rx_crc_err</code></dt>
+              <dd>Number of CRC errors.</dd>
+              <dt><code>rx_errors</code></dt>
+              <dd>
+                Total number of receive errors, greater than or equal
+                to the sum of the above.
+              </dd>
+            </dl>
+          </li>
+          <li>
+            Transmit errors:
+            <dl>
+              <dt><code>tx_dropped</code></dt>
+              <dd>Number of packets dropped by TX.</dd>
+              <dt><code>collisions</code></dt>
+              <dd>Number of collisions.</dd>
+              <dt><code>tx_errors</code></dt>
+              <dd>
+                Total number of transmit errors, greater
+                than or equal to the sum of the above.
+              </dd>
+            </dl>
+          </li>
+        </ul>
+      </column>
     </group>
   </table>