time_t backoff_deadline;
time_t last_received;
time_t last_connected;
+ time_t last_disconnected;
unsigned int packets_sent;
unsigned int seqno;
int last_error;
rc->max_backoff = max_backoff ? max_backoff : 8;
rc->backoff_deadline = TIME_MIN;
rc->last_received = time_now();
- rc->last_connected = time_now();
+ rc->last_connected = TIME_MIN;
+ rc->last_disconnected = TIME_MIN;
rc->seqno = 0;
rc->packets_sent = 0;
}
/* Returns the time at which the last successful connection was made by
- * 'rc'. */
+ * 'rc'. Returns TIME_MIN if never connected. */
time_t
rconn_get_last_connection(const struct rconn *rc)
{
return rc->last_connected;
}
+/* Returns the time at which 'rc' was last disconnected. Returns TIME_MIN
+ * if never disconnected. */
+time_t
+rconn_get_last_disconnect(const struct rconn *rc)
+{
+ return rc->last_disconnected;
+}
+
/* Returns the time at which the last OpenFlow message was received by 'rc'.
* If no packets have been received on 'rc', returns the time at which 'rc'
* was created. */
time_t now = time_now();
if (rc->state & (S_CONNECTING | S_ACTIVE | S_IDLE)) {
+ rc->last_disconnected = now;
vconn_close(rc->vconn);
rc->vconn = NULL;
flush_queue(rc);
question_connectivity(rc);
}
} else {
+ rc->last_disconnected = time_now();
rconn_disconnect(rc);
}
}
unsigned int rconn_get_attempted_connections(const struct rconn *);
unsigned int rconn_get_successful_connections(const struct rconn *);
time_t rconn_get_last_connection(const struct rconn *);
+time_t rconn_get_last_disconnect(const struct rconn *);
time_t rconn_get_last_received(const struct rconn *);
time_t rconn_get_creation_time(const struct rconn *);
unsigned long int rconn_get_total_time_connected(const struct rconn *);
}
void
-ofproto_get_ofproto_controller_info(const struct ofproto * ofproto,
+ofproto_get_ofproto_controller_info(const struct ofproto *ofproto,
struct shash *info)
{
const struct ofconn *ofconn;
HMAP_FOR_EACH (ofconn, hmap_node, &ofproto->controllers) {
const struct rconn *rconn = ofconn->rconn;
+ time_t now = time_now();
+ time_t last_connection = rconn_get_last_connection(rconn);
+ time_t last_disconnect = rconn_get_last_disconnect(rconn);
const int last_error = rconn_get_last_error(rconn);
struct ofproto_controller_info *cinfo = xmalloc(sizeof *cinfo);
cinfo->pairs.values[cinfo->pairs.n++] =
xstrdup(rconn_get_state(rconn));
- if (rconn_is_admitted(rconn)) {
- cinfo->pairs.keys[cinfo->pairs.n] = "time_connected";
- cinfo->pairs.values[cinfo->pairs.n++] =
- xasprintf("%ld", time_now() - rconn_get_last_connection(rconn));
- } else {
- cinfo->pairs.keys[cinfo->pairs.n] = "time_disconnected";
- cinfo->pairs.values[cinfo->pairs.n++] =
- xasprintf("%d", rconn_failure_duration(rconn));
+ if (last_connection != TIME_MIN) {
+ cinfo->pairs.keys[cinfo->pairs.n] = "sec_since_connect";
+ cinfo->pairs.values[cinfo->pairs.n++]
+ = xasprintf("%ld", (long int) (now - last_connection));
+ }
+
+ if (last_disconnect != TIME_MIN) {
+ cinfo->pairs.keys[cinfo->pairs.n] = "sec_since_disconnect";
+ cinfo->pairs.values[cinfo->pairs.n++]
+ = xasprintf("%ld", (long int) (now - last_disconnect));
}
}
}
bool is_connected;
enum nx_role role;
struct {
- const char *keys[3];
- const char *values[3];
+ const char *keys[4];
+ const char *values[4];
size_t n;
} pairs;
};
<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
<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>
+ are: <code>VOID</code> (connection is disabled),
+ <code>BACKOFF</code> (attempting to reconnect at an increasing
+ period), <code>CONNECTING</code> (attempting to connect),
+ <code>ACTIVE</code> (connected, remote host responsive), and
+ <code>IDLE</code> (remote host idle, sending keep-alive). These
+ values may change in the future. They are provided only for human
+ consumption.</dd>
+ <dt><code>sec_since_connect</code></dt>
+ <dd>The amount of time since this controller last successfully
+ connected to the switch (in seconds). Value is empty if controller
+ has never successfully connected.</dd>
+ <dt><code>sec_since_disconnect</code></dt>
+ <dd>The amount of time since this controller last disconnected from
+ the switch (in seconds). Value is empty if controller has never
+ disconnected.</dd>
</dl>
</column>
</group>