Break passive vconns out into separate pvconn routines and data structures.
authorBen Pfaff <blp@nicira.com>
Thu, 11 Sep 2008 22:12:46 +0000 (15:12 -0700)
committerBen Pfaff <blp@nicira.com>
Mon, 15 Sep 2008 21:29:53 +0000 (14:29 -0700)
There really was nothing in common between the active and passive vconns.
This arrangement makes more sense.

14 files changed:
controller/controller.c
include/vconn-provider.h
include/vconn-stream.h
include/vconn.h
lib/rconn.c
lib/vconn-ssl.c
lib/vconn-stream.c
lib/vconn-tcp.c
lib/vconn-unix.c
lib/vconn.c
secchan/secchan.c
switch/datapath.c
switch/datapath.h
switch/switch.c

index 2d79afa..48420c8 100644 (file)
@@ -84,7 +84,7 @@ int
 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;
@@ -112,22 +112,23 @@ main(int argc, char *argv[])
         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");
@@ -145,14 +146,14 @@ main(int argc, char *argv[])
             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];
             }
         }
@@ -183,7 +184,7 @@ main(int argc, char *argv[])
         /* 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++) {
index 8bb8368..f7c47e8 100644 (file)
 #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 {
@@ -80,58 +80,105 @@ struct vconn_class {
     /* 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 */
index d7eb59f..a9b1e7b 100644 (file)
 #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 */
index 6dcfd67..e13e21a 100644 (file)
 
 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 **);
@@ -65,16 +62,21 @@ int vconn_recv_block(struct vconn *, 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 **);
@@ -91,16 +93,4 @@ struct buffer *make_unbuffered_packet_out(const struct buffer *packet,
 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 */
index 991e386..f0ee2bf 100644 (file)
@@ -311,13 +311,8 @@ run_CONNECTING(struct rconn *rc)
     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);
index d899e09..bac39b5 100644 (file)
@@ -663,24 +663,26 @@ struct vconn_class ssl_vconn_class = {
 \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;
@@ -731,24 +733,24 @@ pssl_open(const char *name, char *suffix, struct vconn **vconnp)
     }
 
     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];
@@ -779,19 +781,18 @@ pssl_accept(struct vconn *vconn, struct vconn **new_vconnp)
 }
 
 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
 /*
index f58cc2c..5cf296f 100644 (file)
@@ -256,30 +256,30 @@ static struct vconn_class stream_vconn_class = {
 \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);
@@ -296,25 +296,25 @@ new_pstream_vconn(const char *name, int 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;
@@ -340,16 +340,16 @@ pstream_accept(struct vconn *vconn, struct vconn **new_vconnp)
 }
 
 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
 };
index 7c314cc..bf1851a 100644 (file)
@@ -137,7 +137,7 @@ static int ptcp_accept(int fd, const struct sockaddr *sa, size_t sa_len,
                        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;
@@ -167,7 +167,7 @@ ptcp_open(const char *name, char *suffix, struct vconn **vconnp)
         return error;
     }
 
-    return new_pstream_vconn("ptcp", fd, ptcp_accept, vconnp);
+    return new_pstream_pvconn("ptcp", fd, ptcp_accept, pvconnp);
 }
 
 static int
@@ -188,8 +188,8 @@ ptcp_accept(int fd, const struct sockaddr *sa, size_t sa_len,
     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,
 };
 
index 356109d..cff7d2e 100644 (file)
@@ -92,7 +92,7 @@ static int punix_accept(int fd, const struct sockaddr *sa, size_t sa_len,
                         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;
 
@@ -102,7 +102,7 @@ punix_open(const char *name, char *suffix, struct vconn **vconnp)
         return errno;
     }
 
-    return new_pstream_vconn("punix", fd, punix_accept, vconnp);
+    return new_pstream_pvconn("punix", fd, punix_accept, pvconnp);
 }
 
 static int
@@ -122,8 +122,8 @@ punix_accept(int fd, const struct sockaddr *sa, size_t sa_len,
     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,
 };
 
index 723146a..eba46c8 100644 (file)
 
 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
@@ -81,12 +86,23 @@ check_vconn_classes(void)
         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. */
@@ -143,8 +159,8 @@ vconn_usage(bool active, bool passive)
 }
 
 /* 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
@@ -160,7 +176,6 @@ vconn_open(const char *name, struct vconn **vconnp)
     *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++) {
@@ -174,13 +189,11 @@ vconn_open(const char *name, struct vconn **vconnp)
             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;
 }
 
@@ -224,16 +237,6 @@ vconn_get_name(const struct vconn *vconn)
     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
@@ -256,28 +259,6 @@ vconn_connect(struct vconn *vconn)
     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
@@ -418,9 +399,7 @@ vconn_wait(struct vconn *vconn, enum vconn_wait_type wait)
 {
     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) {
@@ -441,12 +420,6 @@ vconn_connect_wait(struct vconn *vconn)
     vconn_wait(vconn, WAIT_CONNECT);
 }
 
-void
-vconn_accept_wait(struct vconn *vconn)
-{
-    vconn_wait(vconn, WAIT_ACCEPT);
-}
-
 void
 vconn_recv_wait(struct vconn *vconn)
 {
@@ -459,6 +432,78 @@ vconn_send_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
@@ -623,3 +668,10 @@ vconn_init(struct vconn *vconn, struct vconn_class *class, int connect_status,
     vconn->name = xstrdup(name);
 }
 
+void
+pvconn_init(struct pvconn *pvconn, struct pvconn_class *class,
+            const char *name)
+{
+    pvconn->class = class;
+    pvconn->name = xstrdup(name);
+}
index cd6b567..e69a314 100644 (file)
@@ -140,12 +140,12 @@ static struct vlog_rate_limit vrl = VLOG_RATE_LIMIT_INIT(60, 60);
 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 *);
@@ -220,9 +220,9 @@ main(int argc, char *argv[])
     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;
@@ -350,10 +350,10 @@ main(int argc, char *argv[])
             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) {
@@ -369,29 +369,26 @@ main(int argc, char *argv[])
     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));
     }
@@ -448,14 +445,14 @@ get_ofp_packet_eth_header(struct relay *r, struct ofp_packet_in **opip,
 /* 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;
     }
index c709fb7..24744aa 100644 (file)
@@ -117,7 +117,7 @@ struct datapath {
     /* 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;
 
@@ -212,7 +212,7 @@ dp_new(struct datapath **dp_, uint64_t dpid, struct rconn *rconn)
     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) {
@@ -277,10 +277,10 @@ dp_add_port(struct datapath *dp, const char *name)
 }
 
 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
@@ -341,12 +341,12 @@ dp_run(struct datapath *dp)
     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));
@@ -479,8 +479,8 @@ dp_wait(struct datapath *dp)
     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);
     }
 }
 
index 6914782..b2c0f50 100644 (file)
 
 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 *);
 
index 9d307db..1f85b37 100644 (file)
@@ -68,7 +68,7 @@ char serial_num[SERIAL_NUM_LEN] = "None";
 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;
@@ -102,18 +102,15 @@ main(int argc, char *argv[])
         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");
@@ -267,10 +264,10 @@ parse_options(int argc, char *argv[])
             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