bridge: Add controller status to Controller table.
authorAndrew Evans <aevans@nicira.com>
Fri, 21 Jan 2011 19:01:45 +0000 (11:01 -0800)
committerAndrew Evans <aevans@nicira.com>
Mon, 24 Jan 2011 06:16:53 +0000 (22:16 -0800)
Get status information for controller(s) attached to each bridge and store in
Controller table every 5 seconds.

ofproto/ofproto.c
ofproto/ofproto.h
vswitchd/bridge.c
vswitchd/vswitch.ovsschema
vswitchd/vswitch.xml

index 7df8600..aae8568 100644 (file)
@@ -1354,6 +1354,60 @@ ofproto_is_alive(const struct ofproto *p)
     return !hmap_is_empty(&p->controllers);
 }
 
+void
+ofproto_get_ofproto_controller_info(const struct ofproto * ofproto,
+                                    struct shash *info)
+{
+    const struct ofconn *ofconn;
+
+    shash_init(info);
+
+    HMAP_FOR_EACH (ofconn, hmap_node, &ofproto->controllers) {
+        const struct rconn *rconn = ofconn->rconn;
+        const int last_error = rconn_get_last_error(rconn);
+        struct ofproto_controller_info *cinfo = xmalloc(sizeof *cinfo);
+
+        shash_add(info, rconn_get_target(rconn), cinfo);
+
+        cinfo->is_connected = rconn_is_connected(rconn);
+        cinfo->role = ofconn->role;
+
+        cinfo->pairs.n = 0;
+
+        if (last_error == EOF) {
+            cinfo->pairs.keys[cinfo->pairs.n] = "last_error";
+            cinfo->pairs.values[cinfo->pairs.n++] = xstrdup("End of file");
+        } else if (last_error > 0) {
+            cinfo->pairs.keys[cinfo->pairs.n] = "last_error";
+            cinfo->pairs.values[cinfo->pairs.n++] =
+                xstrdup(strerror(last_error));
+        }
+
+        cinfo->pairs.keys[cinfo->pairs.n] = "state";
+        cinfo->pairs.values[cinfo->pairs.n++] =
+            xstrdup(rconn_get_state(rconn));
+
+        cinfo->pairs.keys[cinfo->pairs.n] = "time_in_state";
+        cinfo->pairs.values[cinfo->pairs.n++] =
+            xasprintf("%u", rconn_get_state_elapsed(rconn));
+    }
+}
+
+void
+ofproto_free_ofproto_controller_info(struct shash *info)
+{
+    struct shash_node *node;
+
+    SHASH_FOR_EACH (node, info) {
+        struct ofproto_controller_info *cinfo = node->data;
+        while (cinfo->pairs.n) {
+            free((char *) cinfo->pairs.values[--cinfo->pairs.n]);
+        }
+        free(cinfo);
+    }
+    shash_destroy(info);
+}
+
 /* Deletes port number 'odp_port' from the datapath for 'ofproto'.
  *
  * This is almost the same as calling dpif_port_del() directly on the
index eeaeb6f..8e4e2a6 100644 (file)
@@ -34,8 +34,19 @@ struct cls_rule;
 struct nlattr;
 struct ofhooks;
 struct ofproto;
+struct shash;
 struct svec;
 
+struct ofproto_controller_info {
+    bool is_connected;
+    enum nx_role role;
+    struct {
+        const char *keys[3];
+        const char *values[3];
+        size_t n;
+    } pairs;
+};
+
 struct ofexpired {
     struct flow flow;
     uint64_t packet_count;      /* Packets from subrules. */
@@ -147,6 +158,9 @@ struct ofhooks {
 void ofproto_revalidate(struct ofproto *, tag_type);
 struct tag_set *ofproto_get_revalidate_set(struct ofproto *);
 
+void ofproto_get_ofproto_controller_info(const struct ofproto *, struct shash *);
+void ofproto_free_ofproto_controller_info(struct shash *);
+
 #ifdef  __cplusplus
 }
 #endif
index 680c1ad..1065d6e 100644 (file)
@@ -1318,6 +1318,42 @@ refresh_system_stats(const struct ovsrec_open_vswitch *cfg)
                         &datum);
 }
 
+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
+bridge_refresh_controller_status(const struct bridge *br)
+{
+    struct shash info;
+    const struct ovsrec_controller *cfg;
+
+    ofproto_get_ofproto_controller_info(br->ofproto, &info);
+
+    OVSREC_CONTROLLER_FOR_EACH(cfg, idl) {
+        struct ofproto_controller_info *cinfo = shash_find_data(&info, cfg->target);
+
+        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, (char **) cinfo->pairs.keys,
+                                     (char **) cinfo->pairs.values,
+                                     cinfo->pairs.n);
+    }
+
+    ofproto_free_ofproto_controller_info(&info);
+}
+
 void
 bridge_run(void)
 {
@@ -1393,6 +1429,7 @@ bridge_run(void)
                         iface_refresh_status(iface);
                     }
                 }
+                bridge_refresh_controller_status(br);
             }
             refresh_system_stats(cfg);
             ovsdb_idl_txn_commit(txn);
index 75c4326..c62353c 100644 (file)
@@ -1,5 +1,5 @@
 {"name": "Open_vSwitch",
- "version": "1.0.6",
+ "version": "99.99.99",
  "cksum": "2256400918 14940",
  "tables": {
    "Open_vSwitch": {
                   "min": 0, "max": 1}},
        "external_ids": {
          "type": {"key": "string", "value": "string",
-                  "min": 0, "max": "unlimited"}}}},
+                  "min": 0, "max": "unlimited"}},
+       "is_connected": {
+         "type": "boolean",
+         "ephemeral": true},
+       "role": {
+         "type": {"key": {"type": "string",
+                          "enum": ["set", ["other", "master", "slave"]]},
+                  "min": 0, "max": 1},
+         "ephemeral": true},
+       "status": {
+         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"},
+         "ephemeral": true}}},
    "Manager": {
      "columns": {
        "target": {
index dfa3f20..6565b95 100644 (file)
         unique.  No common key-value pairs are currently defined.
       </column>
     </group>
+
+    <group title="Controller Status">
+      <column name="is_connected">
+        <code>true</code> if currently connected to this controller,
+        <code>false</code> otherwise.
+      </column>
+
+      <column name="role">
+        <p>The level of authority this controller has on the associated
+          bridge. Possible values are:</p>
+        <dl>
+          <dt><code>other</code></dt>
+          <dd>Allows the controller access to all OpenFlow features.</dd>
+        </dl>
+        <dl>
+          <dt><code>master</code></dt>
+          <dd>Equivalent to <code>other</code>, except that there may be at
+            most one master controller at a time.  When a controller configures
+            itself as <code>master</code>, any existing master is demoted to
+            the <code>slave</code>role.</dd>
+        </dl>
+        <dl>
+          <dt><code>slave</code></dt>
+          <dd>Allows the controller read-only access to OpenFlow features.
+            Attempts to modify the flow table will be rejected with an
+            error.  Slave controllers do not receive OFPT_PACKET_IN or
+            OFPT_FLOW_REMOVED messages, but they do receive OFPT_PORT_STATUS
+            messages.</dd>
+        </dl>
+      </column>
+
+      <column name="status">
+        <p>Key-value pairs that report controller status.</p>
+        <dl>
+          <dt><code>last_error</code></dt>
+          <dd>A human-readable description of the last error on the connection
+            to the controller; i.e. <code>strerror(errno)</code>.  This key
+            will exist only if an error has occurred.</dd>
+        </dl>
+        <dl>
+          <dt><code>state</code></dt>
+          <dd>The state of the connection to the controller.  Possible values
+            are: <code>VOID</code>, <code>BACKOFF</code>,
+            <code>CONNECTING</code>, <code>ACTIVE</code>, and
+            <code>IDLE</code>.</dd>
+        </dl>
+        <dl>
+          <dt><code>time_in_state</code></dt>
+          <dd>Seconds since connecting to (if currently connected) or
+            disconnecting from (if currently disconnected) this
+            controller.</dd>
+        </dl>
+      </column>
+    </group>
   </table>
 
   <table name="Manager" title="OVSDB management connection.">