There really was nothing in common between the active and passive vconns.
This arrangement makes more sense.
main(int argc, char *argv[])
{
struct switch_ switches[MAX_SWITCHES];
- struct vconn *listeners[MAX_LISTENERS];
+ struct pvconn *listeners[MAX_LISTENERS];
int n_switches, n_listeners;
int retval;
int i;
int retval;
retval = vconn_open(name, &vconn);
- if (retval) {
- VLOG_ERR("%s: connect: %s", name, strerror(retval));
- continue;
- }
-
- if (vconn_is_passive(vconn)) {
- if (n_listeners >= MAX_LISTENERS) {
- fatal(0, "max %d passive connections", n_listeners);
- }
- listeners[n_listeners++] = vconn;
- } else {
+ if (!retval) {
if (n_switches >= MAX_SWITCHES) {
fatal(0, "max %d switch connections", n_switches);
}
new_switch(&switches[n_switches++], vconn, name);
+ continue;
+ } else if (retval == EAFNOSUPPORT) {
+ struct pvconn *pvconn;
+ retval = pvconn_open(name, &pvconn);
+ if (!retval) {
+ if (n_listeners >= MAX_LISTENERS) {
+ fatal(0, "max %d passive connections", n_listeners);
+ }
+ listeners[n_listeners++] = pvconn;
+ }
}
+ VLOG_ERR("%s: connect: %s", name, strerror(retval));
}
if (n_switches == 0 && n_listeners == 0) {
fatal(0, "no active or passive switch connections");
struct vconn *new_vconn;
int retval;
- retval = vconn_accept(listeners[i], &new_vconn);
+ retval = pvconn_accept(listeners[i], &new_vconn);
if (!retval || retval == EAGAIN) {
if (!retval) {
new_switch(&switches[n_switches++], new_vconn, "tcp");
}
i++;
} else {
- vconn_close(listeners[i]);
+ pvconn_close(listeners[i]);
listeners[i] = listeners[--n_listeners];
}
}
/* Wait for something to happen. */
if (n_switches < MAX_SWITCHES) {
for (i = 0; i < n_listeners; i++) {
- vconn_accept_wait(listeners[i]);
+ pvconn_wait(listeners[i]);
}
}
for (i = 0; i < n_switches; i++) {
#ifndef VCONN_PROVIDER_H
#define VCONN_PROVIDER_H 1
-/* Provider interface, which provide a virtual connection to an OpenFlow
- * device. */
+/* Provider interface to vconns, which provide a virtual connection to an
+ * OpenFlow device. */
#include <assert.h>
#include "vconn.h"
-
-/* Virtual connection to an OpenFlow device.
+\f
+/* Active virtual connection to an OpenFlow device.
*
* This structure should be treated as opaque by vconn implementations. */
struct vconn {
/* Closes 'vconn' and frees associated memory. */
void (*close)(struct vconn *vconn);
- /* Tries to complete the connection on 'vconn', which must be an active
- * vconn. If 'vconn''s connection is complete, returns 0 if the connection
- * was successful or a positive errno value if it failed. If the
- * connection is still in progress, returns EAGAIN.
+ /* Tries to complete the connection on 'vconn'. If 'vconn''s connection is
+ * complete, returns 0 if the connection was successful or a positive errno
+ * value if it failed. If the connection is still in progress, returns
+ * EAGAIN.
*
* The connect function must not block waiting for the connection to
* complete; instead, it should return EAGAIN immediately. */
int (*connect)(struct vconn *vconn);
- /* Tries to accept a new connection on 'vconn', which must be a passive
- * vconn. If successful, stores the new connection in '*new_vconnp' and
- * returns 0. Otherwise, returns a positive errno value.
- *
- * The accept function must not block waiting for a connection. If no
- * connection is ready to be accepted, it should return EAGAIN.
- *
- * Nonnull iff this is a passive vconn (one that accepts connections and
- * does not transfer data). */
- int (*accept)(struct vconn *vconn, struct vconn **new_vconnp);
-
- /* Tries to receive an OpenFlow message from 'vconn', which must be an
- * active vconn. If successful, stores the received message into '*msgp'
- * and returns 0. The caller is responsible for destroying the message
- * with buffer_delete(). On failure, returns a positive errno value and
- * stores a null pointer into '*msgp'.
+ /* Tries to receive an OpenFlow message from 'vconn'. If successful,
+ * stores the received message into '*msgp' and returns 0. The caller is
+ * responsible for destroying the message with buffer_delete(). On
+ * failure, returns a positive errno value and stores a null pointer into
+ * '*msgp'.
*
* If the connection has been closed in the normal fashion, returns EOF.
*
* The recv function must not block waiting for a packet to arrive. If no
- * packets have been received, it should return EAGAIN.
- *
- * Nonnull iff this is an active vconn (one that transfers data and does
- * not accept connections). */
+ * packets have been received, it should return EAGAIN. */
int (*recv)(struct vconn *vconn, struct buffer **msgp);
- /* Tries to queue 'msg' for transmission on 'vconn', which must be an
- * active vconn. If successful, returns 0, in which case ownership of
- * 'msg' is transferred to the vconn. Success does not guarantee that
- * 'msg' has been or ever will be delivered to the peer, only that it has
- * been queued for transmission.
+ /* Tries to queue 'msg' for transmission on 'vconn'. If successful,
+ * returns 0, in which case ownership of 'msg' is transferred to the vconn.
+ * Success does not guarantee that 'msg' has been or ever will be delivered
+ * to the peer, only that it has been queued for transmission.
*
* Returns a positive errno value on failure, in which case the caller
* retains ownership of 'msg'.
*
* The send function must not block. If 'msg' cannot be immediately
- * accepted for transmission, it should return EAGAIN.
- *
- * Nonnull iff this is an active vconn (one that transfers data and does
- * not accept connections). */
+ * accepted for transmission, it should return EAGAIN. */
int (*send)(struct vconn *vconn, struct buffer *msg);
- void (*wait)(struct vconn *vconn, enum vconn_wait_type);
+ /* Arranges for the poll loop to wake up when 'vconn' is ready to take an
+ * action of the given 'type'. */
+ void (*wait)(struct vconn *vconn, enum vconn_wait_type type);
+};
+\f
+/* Passive virtual connection to an OpenFlow device.
+ *
+ * This structure should be treated as opaque by vconn implementations. */
+struct pvconn {
+ struct pvconn_class *class;
+ char *name;
+};
+
+void pvconn_init(struct pvconn *, struct pvconn_class *, const char *name);
+static inline void pvconn_assert_class(const struct pvconn *pvconn,
+ const struct pvconn_class *class)
+{
+ assert(pvconn->class == class);
+}
+
+struct pvconn_class {
+ /* Prefix for connection names, e.g. "ptcp", "pssl". */
+ const char *name;
+
+ /* Attempts to start listening for OpenFlow connections. 'name' is the
+ * full connection name provided by the user, e.g. "nl:0", "tcp:1.2.3.4".
+ * This name is useful for error messages but must not be modified.
+ *
+ * 'suffix' is a copy of 'name' following the colon and may be modified.
+ *
+ * Returns 0 if successful, otherwise a positive errno value. If
+ * successful, stores a pointer to the new connection in '*pvconnp'.
+ *
+ * The listen function must not block. If the connection cannot be
+ * completed immediately, it should return EAGAIN (not EINPROGRESS, as
+ * returned by the connect system call) and continue the connection in the
+ * background. */
+ int (*listen)(const char *name, char *suffix, struct pvconn **pvconnp);
+
+ /* Closes 'pvconn' and frees associated memory. */
+ void (*close)(struct pvconn *pvconn);
+
+ /* Tries to accept a new connection on 'pvconn'. If successful, stores the
+ * new connection in '*new_vconnp' and returns 0. Otherwise, returns a
+ * positive errno value.
+ *
+ * The accept function must not block waiting for a connection. If no
+ * connection is ready to be accepted, it should return EAGAIN. */
+ int (*accept)(struct pvconn *pvconn, struct vconn **new_vconnp);
+
+ /* Arranges for the poll loop to wake up when a connection is ready to be
+ * accepted on 'pvconn'. */
+ void (*wait)(struct pvconn *pvconn);
};
+/* Active and passive vconn classes. */
+extern struct vconn_class tcp_vconn_class;
+extern struct pvconn_class ptcp_pvconn_class;
+extern struct vconn_class unix_vconn_class;
+extern struct pvconn_class punix_pvconn_class;
+#ifdef HAVE_OPENSSL
+extern struct vconn_class ssl_vconn_class;
+extern struct pvconn_class pssl_pvconn_class;
+#endif
+#ifdef HAVE_NETLINK
+extern struct vconn_class netlink_vconn_class;
+#endif
+
#endif /* vconn-provider.h */
#include <stdint.h>
struct vconn;
+struct pvconn;
struct sockaddr;
int new_stream_vconn(const char *name, int fd, int connect_status,
uint32_t ip, struct vconn **vconnp);
-int new_pstream_vconn(const char *name, int fd,
+int new_pstream_pvconn(const char *name, int fd,
int (*accept_cb)(int fd, const struct sockaddr *,
size_t sa_len, struct vconn **),
- struct vconn **vconnp);
+ struct pvconn **pvconnp);
#endif /* vconn-stream.h */
struct buffer;
struct flow;
-struct pollfd;
struct ofp_header;
+struct pvconn;
struct vconn;
-/* Client interface to vconns, which provide a virtual connection to an
- * OpenFlow device. */
-
void vconn_usage(bool active, bool passive);
+
+/* Active vconns: virtual connections to OpenFlow devices. */
int vconn_open(const char *name, struct vconn **);
void vconn_close(struct vconn *);
const char *vconn_get_name(const struct vconn *);
-bool vconn_is_passive(const struct vconn *);
uint32_t vconn_get_ip(const struct vconn *);
int vconn_connect(struct vconn *);
-int vconn_accept(struct vconn *, struct vconn **);
int vconn_recv(struct vconn *, struct buffer **);
int vconn_send(struct vconn *, struct buffer *);
int vconn_transact(struct vconn *, struct buffer *, struct buffer **);
enum vconn_wait_type {
WAIT_CONNECT,
- WAIT_ACCEPT,
WAIT_RECV,
WAIT_SEND
};
void vconn_wait(struct vconn *, enum vconn_wait_type);
void vconn_connect_wait(struct vconn *);
-void vconn_accept_wait(struct vconn *);
void vconn_recv_wait(struct vconn *);
void vconn_send_wait(struct vconn *);
+/* Passive vconns: virtual listeners for incoming OpenFlow connections. */
+int pvconn_open(const char *name, struct pvconn **);
+void pvconn_close(struct pvconn *);
+int pvconn_accept(struct pvconn *, struct vconn **);
+void pvconn_wait(struct pvconn *);
+
+/* OpenFlow protocol utility functions. */
void *make_openflow(size_t openflow_len, uint8_t type, struct buffer **);
void *make_openflow_xid(size_t openflow_len, uint8_t type,
uint32_t xid, struct buffer **);
struct buffer *make_echo_request(void);
struct buffer *make_echo_reply(const struct ofp_header *rq);
-extern struct vconn_class tcp_vconn_class;
-extern struct vconn_class ptcp_vconn_class;
-extern struct vconn_class unix_vconn_class;
-extern struct vconn_class punix_vconn_class;
-#ifdef HAVE_OPENSSL
-extern struct vconn_class ssl_vconn_class;
-extern struct vconn_class pssl_vconn_class;
-#endif
-#ifdef HAVE_NETLINK
-extern struct vconn_class netlink_vconn_class;
-#endif
-
#endif /* vconn.h */
if (!retval) {
VLOG_WARN("%s: connected", rc->name);
rc->n_successful_connections++;
- if (vconn_is_passive(rc->vconn)) {
- 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);
\f
/* Passive SSL. */
-struct pssl_vconn
+struct pssl_pvconn
{
- struct vconn vconn;
+ struct pvconn pvconn;
int fd;
};
-static struct pssl_vconn *
-pssl_vconn_cast(struct vconn *vconn)
+struct pvconn_class pssl_pvconn_class;
+
+static struct pssl_pvconn *
+pssl_pvconn_cast(struct pvconn *pvconn)
{
- vconn_assert_class(vconn, &pssl_vconn_class);
- return CONTAINER_OF(vconn, struct pssl_vconn, vconn);
+ pvconn_assert_class(pvconn, &pssl_pvconn_class);
+ return CONTAINER_OF(pvconn, struct pssl_pvconn, pvconn);
}
static int
-pssl_open(const char *name, char *suffix, struct vconn **vconnp)
+pssl_open(const char *name, char *suffix, struct pvconn **pvconnp)
{
struct sockaddr_in sin;
- struct pssl_vconn *pssl;
+ struct pssl_pvconn *pssl;
int retval;
int fd;
unsigned int yes = 1;
}
pssl = xmalloc(sizeof *pssl);
- vconn_init(&pssl->vconn, &pssl_vconn_class, 0, 0, name);
+ pvconn_init(&pssl->pvconn, &pssl_pvconn_class, name);
pssl->fd = fd;
- *vconnp = &pssl->vconn;
+ *pvconnp = &pssl->pvconn;
return 0;
}
static void
-pssl_close(struct vconn *vconn)
+pssl_close(struct pvconn *pvconn)
{
- struct pssl_vconn *pssl = pssl_vconn_cast(vconn);
+ struct pssl_pvconn *pssl = pssl_pvconn_cast(pvconn);
close(pssl->fd);
free(pssl);
}
static int
-pssl_accept(struct vconn *vconn, struct vconn **new_vconnp)
+pssl_accept(struct pvconn *pvconn, struct vconn **new_vconnp)
{
- struct pssl_vconn *pssl = pssl_vconn_cast(vconn);
+ struct pssl_pvconn *pssl = pssl_pvconn_cast(pvconn);
struct sockaddr_in sin;
socklen_t sin_len = sizeof sin;
char name[128];
}
static void
-pssl_wait(struct vconn *vconn, enum vconn_wait_type wait)
+pssl_wait(struct pvconn *pvconn)
{
- struct pssl_vconn *pssl = pssl_vconn_cast(vconn);
- assert(wait == WAIT_ACCEPT);
+ struct pssl_pvconn *pssl = pssl_pvconn_cast(pvconn);
poll_fd_wait(pssl->fd, POLLIN);
}
-struct vconn_class pssl_vconn_class = {
- .name = "pssl",
- .open = pssl_open,
- .close = pssl_close,
- .accept = pssl_accept,
- .wait = pssl_wait,
+struct pvconn_class pssl_pvconn_class = {
+ "pssl",
+ pssl_open,
+ pssl_close,
+ pssl_accept,
+ pssl_wait,
};
\f
/*
\f
/* Passive stream socket vconn. */
-struct pstream_vconn
+struct pstream_pvconn
{
- struct vconn vconn;
+ struct pvconn pvconn;
int fd;
int (*accept_cb)(int fd, const struct sockaddr *, size_t sa_len,
struct vconn **);
};
-static struct vconn_class pstream_vconn_class;
+static struct pvconn_class pstream_pvconn_class;
-static struct pstream_vconn *
-pstream_vconn_cast(struct vconn *vconn)
+static struct pstream_pvconn *
+pstream_pvconn_cast(struct pvconn *pvconn)
{
- vconn_assert_class(vconn, &pstream_vconn_class);
- return CONTAINER_OF(vconn, struct pstream_vconn, vconn);
+ pvconn_assert_class(pvconn, &pstream_pvconn_class);
+ return CONTAINER_OF(pvconn, struct pstream_pvconn, pvconn);
}
int
-new_pstream_vconn(const char *name, int fd,
+new_pstream_pvconn(const char *name, int fd,
int (*accept_cb)(int fd, const struct sockaddr *,
size_t sa_len, struct vconn **),
- struct vconn **vconnp)
+ struct pvconn **pvconnp)
{
- struct pstream_vconn *ps;
+ struct pstream_pvconn *ps;
int retval;
retval = set_nonblocking(fd);
}
ps = xmalloc(sizeof *ps);
- vconn_init(&ps->vconn, &pstream_vconn_class, 0, 0, name);
+ pvconn_init(&ps->pvconn, &pstream_pvconn_class, name);
ps->fd = fd;
ps->accept_cb = accept_cb;
- *vconnp = &ps->vconn;
+ *pvconnp = &ps->pvconn;
return 0;
}
static void
-pstream_close(struct vconn *vconn)
+pstream_close(struct pvconn *pvconn)
{
- struct pstream_vconn *ps = pstream_vconn_cast(vconn);
+ struct pstream_pvconn *ps = pstream_pvconn_cast(pvconn);
close(ps->fd);
free(ps);
}
static int
-pstream_accept(struct vconn *vconn, struct vconn **new_vconnp)
+pstream_accept(struct pvconn *pvconn, struct vconn **new_vconnp)
{
- struct pstream_vconn *ps = pstream_vconn_cast(vconn);
+ struct pstream_pvconn *ps = pstream_pvconn_cast(pvconn);
struct sockaddr_storage ss;
socklen_t ss_len = sizeof ss;
int new_fd;
}
static void
-pstream_wait(struct vconn *vconn, enum vconn_wait_type wait)
+pstream_wait(struct pvconn *pvconn)
{
- struct pstream_vconn *ps = pstream_vconn_cast(vconn);
- assert(wait == WAIT_ACCEPT);
+ struct pstream_pvconn *ps = pstream_pvconn_cast(pvconn);
poll_fd_wait(ps->fd, POLLIN);
}
-static struct vconn_class pstream_vconn_class = {
- .name = "pstream",
- .close = pstream_close,
- .accept = pstream_accept,
- .wait = pstream_wait
+static struct pvconn_class pstream_pvconn_class = {
+ "pstream",
+ NULL,
+ pstream_close,
+ pstream_accept,
+ pstream_wait
};
struct vconn **vconnp);
static int
-ptcp_open(const char *name, char *suffix, struct vconn **vconnp)
+ptcp_open(const char *name, char *suffix, struct pvconn **pvconnp)
{
struct sockaddr_in sin;
int retval;
return error;
}
- return new_pstream_vconn("ptcp", fd, ptcp_accept, vconnp);
+ return new_pstream_pvconn("ptcp", fd, ptcp_accept, pvconnp);
}
static int
return new_tcp_vconn(name, fd, 0, sin, vconnp);
}
-struct vconn_class ptcp_vconn_class = {
- .name = "ptcp",
- .open = ptcp_open,
+struct pvconn_class ptcp_pvconn_class = {
+ "ptcp",
+ ptcp_open,
};
struct vconn **vconnp);
static int
-punix_open(const char *name, char *suffix, struct vconn **vconnp)
+punix_open(const char *name, char *suffix, struct pvconn **pvconnp)
{
int fd;
return errno;
}
- return new_pstream_vconn("punix", fd, punix_accept, vconnp);
+ return new_pstream_pvconn("punix", fd, punix_accept, pvconnp);
}
static int
return new_stream_vconn(name, fd, 0, 0, vconnp);
}
-struct vconn_class punix_vconn_class = {
- .name = "punix",
- .open = punix_open,
+struct pvconn_class punix_pvconn_class = {
+ "punix",
+ punix_open,
};
static struct vconn_class *vconn_classes[] = {
&tcp_vconn_class,
- &ptcp_vconn_class,
+ &unix_vconn_class,
#ifdef HAVE_NETLINK
&netlink_vconn_class,
#endif
#ifdef HAVE_OPENSSL
&ssl_vconn_class,
- &pssl_vconn_class,
#endif
- &unix_vconn_class,
- &punix_vconn_class,
+};
+
+static struct pvconn_class *pvconn_classes[] = {
+ &ptcp_pvconn_class,
+ &punix_pvconn_class,
+#ifdef HAVE_OPENSSL
+ &pssl_pvconn_class,
+#endif
};
/* High rate limit because most of the rate-limiting here is individual
struct vconn_class *class = vconn_classes[i];
assert(class->name != NULL);
assert(class->open != NULL);
- if (class->close || class->accept || class->recv || class->send
- || class->wait) {
+ if (class->close || class->recv || class->send || class->wait) {
assert(class->close != NULL);
- assert(class->accept
- ? !class->recv && !class->send
- : class->recv && class->send);
+ assert(class->recv != NULL);
+ assert(class->send != NULL);
+ assert(class->wait != NULL);
+ } else {
+ /* This class delegates to another one. */
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pvconn_classes); i++) {
+ struct pvconn_class *class = pvconn_classes[i];
+ assert(class->name != NULL);
+ assert(class->listen != NULL);
+ if (class->close || class->accept || class->wait) {
+ assert(class->close != NULL);
+ assert(class->accept != NULL);
assert(class->wait != NULL);
} else {
/* This class delegates to another one. */
}
/* Attempts to connect to an OpenFlow device. 'name' is a connection name in
- * the form "TYPE:ARGS", where TYPE is the vconn class's name and ARGS are
- * vconn class-specific.
+ * the form "TYPE:ARGS", where TYPE is an active vconn class's name and ARGS
+ * are vconn class-specific.
*
* Returns 0 if successful, otherwise a positive errno value. If successful,
* stores a pointer to the new connection in '*vconnp', otherwise a null
*vconnp = NULL;
prefix_len = strcspn(name, ":");
if (prefix_len == strlen(name)) {
- error(0, "`%s' not correct format for peer name", name);
return EAFNOSUPPORT;
}
for (i = 0; i < ARRAY_SIZE(vconn_classes); i++) {
if (!retval) {
assert(vconn->connect_status != EAGAIN
|| vconn->class->connect);
- vconn->name = xstrdup(name);
*vconnp = vconn;
}
return retval;
}
}
- error(0, "unknown peer type `%.*s'", (int) prefix_len, name);
return EAFNOSUPPORT;
}
return vconn->name;
}
-/* Returns true if 'vconn' is a passive vconn, that is, its purpose is to
- * wait for connections to arrive, not to transfer data. Returns false if
- * 'vconn' is an active vconn, that is, its purpose is to transfer data, not
- * to wait for new connections to arrive. */
-bool
-vconn_is_passive(const struct vconn *vconn)
-{
- return vconn->class->accept != NULL;
-}
-
/* Returns the IP address of the peer, or 0 if the peer is not connected over
* an IP-based protocol or if its IP address is not yet known. */
uint32_t
return vconn->connect_status;
}
-/* Tries to accept a new connection on 'vconn', which must be a passive vconn.
- * If successful, stores the new connection in '*new_vconn' and returns 0.
- * Otherwise, returns a positive errno value.
- *
- * vconn_accept will not block waiting for a connection. If no connection is
- * ready to be accepted, it returns EAGAIN immediately. */
-int
-vconn_accept(struct vconn *vconn, struct vconn **new_vconn)
-{
- int retval;
-
- retval = (vconn->class->accept)(vconn, new_vconn);
-
- if (retval) {
- *new_vconn = NULL;
- } else {
- assert((*new_vconn)->connect_status != EAGAIN
- || (*new_vconn)->class->connect);
- }
- return retval;
-}
-
/* Tries to receive an OpenFlow message from 'vconn', which must be an active
* vconn. If successful, stores the received message into '*msgp' and returns
* 0. The caller is responsible for destroying the message with
{
int connect_status;
- assert(vconn_is_passive(vconn)
- ? wait == WAIT_ACCEPT || wait == WAIT_CONNECT
- : wait == WAIT_CONNECT || wait == WAIT_RECV || wait == WAIT_SEND);
+ assert(wait == WAIT_CONNECT || wait == WAIT_RECV || wait == WAIT_SEND);
connect_status = vconn_connect(vconn);
if (connect_status) {
vconn_wait(vconn, WAIT_CONNECT);
}
-void
-vconn_accept_wait(struct vconn *vconn)
-{
- vconn_wait(vconn, WAIT_ACCEPT);
-}
-
void
vconn_recv_wait(struct vconn *vconn)
{
vconn_wait(vconn, WAIT_SEND);
}
+/* Attempts to start listening for OpenFlow connections. 'name' is a
+ * connection name in the form "TYPE:ARGS", where TYPE is an passive vconn
+ * class's name and ARGS are vconn class-specific.
+ *
+ * Returns 0 if successful, otherwise a positive errno value. If successful,
+ * stores a pointer to the new connection in '*pvconnp', otherwise a null
+ * pointer. */
+int
+pvconn_open(const char *name, struct pvconn **pvconnp)
+{
+ size_t prefix_len;
+ size_t i;
+
+ check_vconn_classes();
+
+ *pvconnp = NULL;
+ prefix_len = strcspn(name, ":");
+ if (prefix_len == strlen(name)) {
+ return EAFNOSUPPORT;
+ }
+ for (i = 0; i < ARRAY_SIZE(pvconn_classes); i++) {
+ struct pvconn_class *class = pvconn_classes[i];
+ if (strlen(class->name) == prefix_len
+ && !memcmp(class->name, name, prefix_len)) {
+ char *suffix_copy = xstrdup(name + prefix_len + 1);
+ int retval = class->listen(name, suffix_copy, pvconnp);
+ free(suffix_copy);
+ if (retval) {
+ *pvconnp = NULL;
+ }
+ return retval;
+ }
+ }
+ return EAFNOSUPPORT;
+}
+
+/* Closes 'pvconn'. */
+void
+pvconn_close(struct pvconn *pvconn)
+{
+ if (pvconn != NULL) {
+ char *name = pvconn->name;
+ (pvconn->class->close)(pvconn);
+ free(name);
+ }
+}
+
+/* Tries to accept a new connection on 'pvconn'. If successful, stores the new
+ * connection in '*new_vconn' and returns 0. Otherwise, returns a positive
+ * errno value.
+ *
+ * pvconn_accept() will not block waiting for a connection. If no connection
+ * is ready to be accepted, it returns EAGAIN immediately. */
+int
+pvconn_accept(struct pvconn *pvconn, struct vconn **new_vconn)
+{
+ int retval = (pvconn->class->accept)(pvconn, new_vconn);
+ if (retval) {
+ *new_vconn = NULL;
+ } else {
+ assert((*new_vconn)->connect_status == 0
+ || (*new_vconn)->class->connect);
+ }
+ return retval;
+}
+
+void
+pvconn_wait(struct pvconn *pvconn)
+{
+ (pvconn->class->wait)(pvconn);
+}
+
/* Allocates and returns the first byte of a buffer 'openflow_len' bytes long,
* containing an OpenFlow header with the given 'type' and a random transaction
* id. Stores the new buffer in '*bufferp'. The caller must free the buffer
vconn->name = xstrdup(name);
}
+void
+pvconn_init(struct pvconn *pvconn, struct pvconn_class *class,
+ const char *name)
+{
+ pvconn->class = class;
+ pvconn->name = xstrdup(name);
+}
static void parse_options(int argc, char *argv[], struct settings *);
static void usage(void) NO_RETURN;
-static struct vconn *open_passive_vconn(const char *name);
-static struct vconn *accept_vconn(struct vconn *vconn);
+static struct pvconn *open_passive_vconn(const char *name);
+static struct vconn *accept_vconn(struct pvconn *pvconn);
static struct relay *relay_create(struct rconn *local, struct rconn *remote,
bool is_mgmt_conn);
-static struct relay *relay_accept(const struct settings *, struct vconn *);
+static struct relay *relay_accept(const struct settings *, struct pvconn *);
static void relay_run(struct relay *, const struct hook[], size_t n_hooks);
static void relay_wait(struct relay *);
static void relay_destroy(struct relay *);
struct hook hooks[8];
size_t n_hooks = 0;
- struct vconn *monitor;
+ struct pvconn *monitor;
- struct vconn *listeners[MAX_MGMT];
+ struct pvconn *listeners[MAX_MGMT];
size_t n_listeners;
struct rconn *local_rconn, *remote_rconn;
relay_wait(r);
}
for (i = 0; i < n_listeners; i++) {
- vconn_accept_wait(listeners[i]);
+ pvconn_wait(listeners[i]);
}
if (monitor) {
- vconn_accept_wait(monitor);
+ pvconn_wait(monitor);
}
for (i = 0; i < n_hooks; i++) {
if (hooks[i].wait_cb) {
return 0;
}
-static struct vconn *
-open_passive_vconn(const char *name)
+static struct pvconn *
+open_passive_vconn(const char *name)
{
- struct vconn *vconn;
+ struct pvconn *pvconn;
int retval;
- retval = vconn_open(name, &vconn);
+ retval = pvconn_open(name, &pvconn);
if (retval && retval != EAGAIN) {
fatal(retval, "opening %s", name);
}
- if (!vconn_is_passive(vconn)) {
- fatal(0, "%s is not a passive vconn", name);
- }
- return vconn;
+ return pvconn;
}
static struct vconn *
-accept_vconn(struct vconn *vconn)
+accept_vconn(struct pvconn *pvconn)
{
struct vconn *new;
int retval;
- retval = vconn_accept(vconn, &new);
+ retval = pvconn_accept(pvconn, &new);
if (retval && retval != EAGAIN) {
VLOG_WARN_RL(&vrl, "accept failed (%s)", strerror(retval));
}
/* OpenFlow message relaying. */
static struct relay *
-relay_accept(const struct settings *s, struct vconn *listen_vconn)
+relay_accept(const struct settings *s, struct pvconn *pvconn)
{
struct vconn *new_remote, *new_local;
char *nl_name_without_subscription;
struct rconn *r1, *r2;
int retval;
- new_remote = accept_vconn(listen_vconn);
+ new_remote = accept_vconn(pvconn);
if (!new_remote) {
return NULL;
}
/* Remote connections. */
struct remote *controller; /* Connection to controller. */
struct list remotes; /* All connections (including controller). */
- struct vconn *listen_vconn;
+ struct pvconn *listen_pvconn;
time_t last_timeout;
dp->last_timeout = time_now();
list_init(&dp->remotes);
dp->controller = remote_create(dp, rconn);
- dp->listen_vconn = NULL;
+ dp->listen_pvconn = NULL;
dp->id = dpid <= UINT64_C(0xffffffffffff) ? dpid : gen_datapath_id();
dp->chain = chain_create();
if (!dp->chain) {
}
void
-dp_add_listen_vconn(struct datapath *dp, struct vconn *listen_vconn)
+dp_add_listen_pvconn(struct datapath *dp, struct pvconn *listen_pvconn)
{
- assert(!dp->listen_vconn);
- dp->listen_vconn = listen_vconn;
+ assert(!dp->listen_pvconn);
+ dp->listen_pvconn = listen_pvconn;
}
void
LIST_FOR_EACH_SAFE (r, rn, struct remote, node, &dp->remotes) {
remote_run(dp, r);
}
- if (dp->listen_vconn) {
+ if (dp->listen_pvconn) {
for (;;) {
struct vconn *new_vconn;
int retval;
- retval = vconn_accept(dp->listen_vconn, &new_vconn);
+ retval = pvconn_accept(dp->listen_pvconn, &new_vconn);
if (retval) {
if (retval != EAGAIN) {
VLOG_WARN_RL(&rl, "accept failed (%s)", strerror(retval));
LIST_FOR_EACH (r, struct remote, node, &dp->remotes) {
remote_wait(r);
}
- if (dp->listen_vconn) {
- vconn_accept_wait(dp->listen_vconn);
+ if (dp->listen_pvconn) {
+ pvconn_wait(dp->listen_pvconn);
}
}
struct datapath;
struct rconn;
-struct vconn;
+struct pvconn;
int dp_new(struct datapath **, uint64_t dpid, struct rconn *);
int dp_add_port(struct datapath *, const char *netdev);
-void dp_add_listen_vconn(struct datapath *, struct vconn *);
+void dp_add_listen_pvconn(struct datapath *, struct pvconn *);
void dp_run(struct datapath *);
void dp_wait(struct datapath *);
static void parse_options(int argc, char *argv[]);
static void usage(void) NO_RETURN;
-static const char *listen_vconn_name;
+static const char *listen_pvconn_name;
static struct datapath *dp;
static uint64_t dpid = UINT64_MAX;
static char *port_list;
fatal(0, "no support for %s vconn", argv[optind]);
}
error = dp_new(&dp, dpid, rconn);
- if (listen_vconn_name) {
- struct vconn *listen_vconn;
+ if (listen_pvconn_name) {
+ struct pvconn *listen_pvconn;
int retval;
-
- retval = vconn_open(listen_vconn_name, &listen_vconn);
+
+ retval = pvconn_open(listen_pvconn_name, &listen_pvconn);
if (retval && retval != EAGAIN) {
- fatal(retval, "opening %s", listen_vconn_name);
- }
- if (!vconn_is_passive(listen_vconn)) {
- fatal(0, "%s is not a passive vconn", listen_vconn_name);
+ fatal(retval, "opening %s", listen_pvconn_name);
}
- dp_add_listen_vconn(dp, listen_vconn);
+ dp_add_listen_pvconn(dp, listen_pvconn);
}
if (error) {
fatal(error, "could not create datapath");
break;
case 'l':
- if (listen_vconn_name) {
+ if (listen_pvconn_name) {
fatal(0, "-l or --listen may be only specified once");
}
- listen_vconn_name = optarg;
+ listen_pvconn_name = optarg;
break;
VCONN_SSL_OPTION_HANDLERS