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
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. */
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
&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)
{
iface_refresh_status(iface);
}
}
+ bridge_refresh_controller_status(br);
}
refresh_system_stats(cfg);
ovsdb_idl_txn_commit(txn);
{"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": {
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.">