#include <stdlib.h>
#include <string.h>
#include "ofpbuf.h"
+#include "openflow.h"
#include "poll-loop.h"
#include "sat-math.h"
#include "timeval.h"
* an echo request as an inactivity probe packet. We should receive back
* a response. */
int probe_interval; /* Secs of inactivity before sending probe. */
+
+ /* Messages sent or received are copied to the monitor connections. */
+#define MAX_MONITORS 8
+ struct vconn *monitors[8];
+ size_t n_monitors;
};
static unsigned int elapsed_in_this_state(const struct rconn *);
static void disconnect(struct rconn *, int error);
static void flush_queue(struct rconn *);
static void question_connectivity(struct rconn *);
+static void copy_to_monitor(struct rconn *, const struct ofpbuf *);
/* Creates a new rconn, connects it (reliably) to 'name', and returns it. */
struct rconn *
rc->probe_interval = probe_interval ? MAX(5, probe_interval) : 0;
+ rc->n_monitors = 0;
+
return rc;
}
VLOG_WARN("%s: connecting...", rc->name);
rc->n_attempted_connections++;
- retval = vconn_open(rc->name, &rc->vconn);
+ retval = vconn_open(rc->name, OFP_VERSION, &rc->vconn);
if (!retval) {
rc->backoff_deadline = time_now() + rc->backoff;
state_transition(rc, S_CONNECTING);
if (!retval) {
VLOG_WARN("%s: connected", rc->name);
rc->n_successful_connections++;
- if (vconn_is_passive(rc->vconn)) {
- ofp_error(0, "%s: passive vconn not supported", rc->name);
- state_transition(rc, S_VOID);
- } else {
- state_transition(rc, S_ACTIVE);
- rc->last_connected = rc->state_entered;
- }
+ state_transition(rc, S_ACTIVE);
+ rc->last_connected = rc->state_entered;
} else if (retval != EAGAIN) {
VLOG_WARN("%s: connection failed (%s)", rc->name, strerror(retval));
disconnect(rc, retval);
struct ofpbuf *buffer;
int error = vconn_recv(rc->vconn, &buffer);
if (!error) {
+ copy_to_monitor(rc, buffer);
rc->last_received = time_now();
rc->packets_received++;
if (rc->state == S_IDLE) {
rconn_send(struct rconn *rc, struct ofpbuf *b, int *n_queued)
{
if (rconn_is_connected(rc)) {
+ copy_to_monitor(rc, b);
b->private = n_queued;
if (n_queued) {
++*n_queued;
/* Sends 'b' on 'rc'. Increments '*n_queued' while the packet is in flight; it
* will be decremented when it has been sent (or discarded due to
* disconnection). Returns 0 if successful, EAGAIN if '*n_queued' is already
- * at least as large of 'queue_limit', or ENOTCONN if 'rc' is not currently
+ * at least as large as 'queue_limit', or ENOTCONN if 'rc' is not currently
* connected. Regardless of return value, 'b' is destroyed.
*
* Because 'b' may be sent (or discarded) before this function returns, the
return rc->packets_sent;
}
+/* Adds 'vconn' to 'rc' as a monitoring connection, to which all messages sent
+ * and received on 'rconn' will be copied. 'rc' takes ownership of 'vconn'. */
+void
+rconn_add_monitor(struct rconn *rc, struct vconn *vconn)
+{
+ if (rc->n_monitors < ARRAY_SIZE(rc->monitors)) {
+ VLOG_WARN("new monitor connection from %s", vconn_get_name(vconn));
+ rc->monitors[rc->n_monitors++] = vconn;
+ } else {
+ VLOG_DBG("too many monitor connections, discarding %s",
+ vconn_get_name(vconn));
+ vconn_close(vconn);
+ }
+}
+
/* Returns 'rc''s name (the 'name' argument passed to rconn_new()). */
const char *
rconn_get_name(const struct rconn *rc)
rc->last_questioned = now;
}
}
+
+static void
+copy_to_monitor(struct rconn *rc, const struct ofpbuf *b)
+{
+ struct ofpbuf *clone = NULL;
+ int retval;
+ size_t i;
+
+ for (i = 0; i < rc->n_monitors; ) {
+ struct vconn *vconn = rc->monitors[i];
+
+ if (!clone) {
+ clone = ofpbuf_clone(b);
+ }
+ retval = vconn_send(vconn, clone);
+ if (!retval) {
+ clone = NULL;
+ } else if (retval != EAGAIN) {
+ VLOG_DBG("%s: closing monitor connection to %s: %s",
+ rconn_get_name(rc), vconn_get_name(vconn),
+ strerror(retval));
+ rc->monitors[i] = rc->monitors[--rc->n_monitors];
+ continue;
+ }
+ i++;
+ }
+ ofpbuf_delete(clone);
+}