Add new "fd" vconn, which takes a file descriptor number as argument.
authorBen Pfaff <blp@nicira.com>
Wed, 17 Dec 2008 00:57:40 +0000 (16:57 -0800)
committerBen Pfaff <blp@nicira.com>
Wed, 17 Dec 2008 00:57:40 +0000 (16:57 -0800)
This requires introducing the concept of a "reconnectable" vconn.  A vconn
is reconnectable if, when it is closed, it is possible to try to reconnect
to it using the name that was originally used.  This is the case for all
existing vconn types, but it is not true for fd vconns, because closing a
fd vconn closes the specified file descriptor, and thus attempting to
reopen it will get an EBADF error.

An rconn is not reliable if it is connected to a vconn that is not
reconnectable.

13 files changed:
lib/automake.mk
lib/rconn.c
lib/vconn-fd.c [new file with mode: 0644]
lib/vconn-netlink.c
lib/vconn-provider.h
lib/vconn-ssl.c
lib/vconn-stream.c
lib/vconn-stream.h
lib/vconn-tcp.c
lib/vconn-unix.c
lib/vconn.c
lib/vconn.h
lib/vlog-modules.def

index 6b2af618cc54ec14808a5264e973b4ee5e65e93b..8f2c09f8aba0509454118583c5a8fc903b4dd6d2 100644 (file)
@@ -58,6 +58,7 @@ lib_libopenflow_a_SOURCES = \
        lib/type-props.h \
        lib/util.c \
        lib/util.h \
+       lib/vconn-fd.c \
        lib/vconn-provider.h \
        lib/vconn-ssl.h \
        lib/vconn-stream.c \
index ba606fb5eaba2ee1881887d024004dff169c1773..086cf7d9d3cc77c0efffdd84a7235a9951809bd7 100644 (file)
@@ -298,6 +298,9 @@ reconnect(struct rconn *rc)
     rc->n_attempted_connections++;
     retval = vconn_open(rc->name, OFP_VERSION, &rc->vconn);
     if (!retval) {
+        if (!vconn_is_reconnectable(rc->vconn)) {
+            rc->reliable = false;
+        }
         rc->backoff_deadline = time_now() + rc->backoff;
         state_transition(rc, S_CONNECTING);
     } else {
diff --git a/lib/vconn-fd.c b/lib/vconn-fd.c
new file mode 100644 (file)
index 0000000..ccc6768
--- /dev/null
@@ -0,0 +1,77 @@
+/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
+ * Junior University
+ *
+ * We are making the OpenFlow specification and associated documentation
+ * (Software) available for public use and benefit with the expectation
+ * that others will use, modify and enhance the Software and contribute
+ * those enhancements back to the community. However, since we would
+ * like to make the Software available for broadest use, with as few
+ * restrictions as possible permission is hereby granted, free of
+ * charge, to any person obtaining a copy of this Software to deal in
+ * the Software under the copyrights without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The name and trademarks of copyright holder(s) may NOT be used in
+ * advertising or publicity pertaining to the Software or any
+ * derivatives without specific, written prior permission.
+ */
+
+#include <config.h>
+#include "vconn.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "util.h"
+#include "vconn-provider.h"
+#include "vconn-stream.h"
+
+#include "vlog.h"
+#define THIS_MODULE VLM_vconn_fd
+
+/* File descriptor. */
+
+static int
+fd_open(const char *name, char *suffix, struct vconn **vconnp)
+{
+    int fd = atoi(suffix);
+    struct stat s;
+
+    /* Check that 'fd' is really open and is really the right type of fd. */
+    if (fstat(fd, &s) < 0) {
+        VLOG_ERR("%s: failed to stat file descriptor %d: %s",
+                 name, fd, strerror(errno));
+        return errno;
+    }
+    if (!S_ISSOCK(s.st_mode)) {
+        VLOG_ERR("%s: file descriptor %d is not a socket", name, fd);
+        return errno;
+    }
+
+    return new_stream_vconn(name, fd, 0, 0, false, vconnp);
+}
+
+struct vconn_class fd_vconn_class = {
+    "fd",                       /* name */
+    fd_open,                    /* open */
+    NULL,                       /* close */
+    NULL,                       /* connect */
+    NULL,                       /* recv */
+    NULL,                       /* send */
+    NULL,                       /* wait */
+};
index f7b86777e5d008b7899dd4d7784356aa0b0323bc..91faa71373165922dccd3b839fcfc89408903fec 100644 (file)
@@ -85,7 +85,7 @@ netlink_open(const char *name, char *suffix, struct vconn **vconnp)
     }
 
     netlink = xmalloc(sizeof *netlink);
-    vconn_init(&netlink->vconn, &netlink_vconn_class, 0, 0, name);
+    vconn_init(&netlink->vconn, &netlink_vconn_class, 0, 0, name, true);
     retval = dpif_open(subscribe ? dp_idx : -1, &netlink->dp);
     netlink->dp_idx = dp_idx;
     if (retval) {
index cf033afc87c5c284df47662e75de1de0cc2271f0..caf739b24c53004e1e487476ec43cf2128bf7800 100644 (file)
@@ -53,10 +53,11 @@ struct vconn {
     int version;
     uint32_t ip;
     char *name;
+    bool reconnectable;
 };
 
 void vconn_init(struct vconn *, struct vconn_class *, int connect_status,
-                uint32_t ip, const char *name);
+                uint32_t ip, const char *name, bool reconnectable);
 static inline void vconn_assert_class(const struct vconn *vconn,
                                       const struct vconn_class *class)
 {
@@ -178,6 +179,7 @@ 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;
+extern struct vconn_class fd_vconn_class;
 #ifdef HAVE_OPENSSL
 extern struct vconn_class ssl_vconn_class;
 extern struct pvconn_class pssl_pvconn_class;
index 6d24e277bfe05a908f135b21114a0ab8625e929a..a00906c963b73c0dd46240ef06d6327e784b5a8a 100644 (file)
@@ -250,7 +250,7 @@ new_ssl_vconn(const char *name, int fd, enum session_type type,
     /* Create and return the ssl_vconn. */
     sslv = xmalloc(sizeof *sslv);
     vconn_init(&sslv->vconn, &ssl_vconn_class, EAGAIN, sin->sin_addr.s_addr,
-               name);
+               name, true);
     sslv->state = state;
     sslv->type = type;
     sslv->fd = fd;
index 0b8526110fea6cb30a9ca5656702d673026b1f39..cdbea1fb29c1a2fd31979d8ba8d492b3bf1c560d 100644 (file)
@@ -70,12 +70,13 @@ static void stream_clear_txbuf(struct stream_vconn *);
 
 int
 new_stream_vconn(const char *name, int fd, int connect_status,
-                 uint32_t ip, struct vconn **vconnp)
+                 uint32_t ip, bool reconnectable, struct vconn **vconnp)
 {
     struct stream_vconn *s;
 
     s = xmalloc(sizeof *s);
-    vconn_init(&s->vconn, &stream_vconn_class, connect_status, ip, name);
+    vconn_init(&s->vconn, &stream_vconn_class, connect_status, ip, name,
+               reconnectable);
     s->fd = fd;
     s->txbuf = NULL;
     s->tx_waiter = NULL;
index a9b1e7b3d79c0dcd8290aff621ff0cadfab5fee6..7238a1f14294cbbc7d5f0c2bcc497d96e3edc50c 100644 (file)
@@ -34,6 +34,7 @@
 #ifndef VCONN_STREAM_H
 #define VCONN_STREAM_H 1
 
+#include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
 
@@ -42,7 +43,7 @@ struct pvconn;
 struct sockaddr;
 
 int new_stream_vconn(const char *name, int fd, int connect_status,
-                     uint32_t ip, struct vconn **vconnp);
+                     uint32_t ip, bool reconnectable, struct vconn **vconnp);
 int new_pstream_pvconn(const char *name, int fd,
                       int (*accept_cb)(int fd, const struct sockaddr *,
                                        size_t sa_len, struct vconn **),
index 79d833223685e60f28a088bd92b78d10969d11f5..4049f00c79bbfb094d84d40f6ad9c51db7a76c1a 100644 (file)
@@ -68,7 +68,7 @@ new_tcp_vconn(const char *name, int fd, int connect_status,
     }
 
     return new_stream_vconn(name, fd, connect_status, sin->sin_addr.s_addr,
-                            vconnp);
+                            true, vconnp);
 }
 
 static int
index b1a7d8a75ef77fc153cb34680d056ee8358dab20..48c27470e083413782a095040fb04a20bab4c50c 100644 (file)
@@ -77,7 +77,7 @@ unix_open(const char *name, char *suffix, struct vconn **vconnp)
     }
 
     return new_stream_vconn(name, fd, check_connection_completion(fd),
-                            0, vconnp);
+                            0, true, vconnp);
 }
 
 struct vconn_class unix_vconn_class = {
@@ -122,7 +122,7 @@ punix_accept(int fd, const struct sockaddr *sa, size_t sa_len,
     } else {
         strcpy(name, "unix");
     }
-    return new_stream_vconn(name, fd, 0, 0, vconnp);
+    return new_stream_vconn(name, fd, 0, 0, true, vconnp);
 }
 
 struct pvconn_class punix_pvconn_class = {
index e630258b22bff7c94b5031236ad6272084447412..6b0bc71a61f88a7ca5a32a93b0d0d03dd5e1f9e6 100644 (file)
@@ -74,6 +74,7 @@ static struct vconn_class *vconn_classes[] = {
 #ifdef HAVE_OPENSSL
     &ssl_vconn_class,
 #endif
+    &fd_vconn_class,
 };
 
 static struct pvconn_class *pvconn_classes[] = {
@@ -152,6 +153,7 @@ vconn_usage(bool active, bool passive, bool bootstrap UNUSED)
                "SSL PORT (default: %d) on remote HOST\n", OFP_SSL_PORT);
 #endif
         printf("  unix:FILE               Unix domain socket named FILE\n");
+        printf("  fd:N                    File descriptor N\n");
     }
 
     if (passive) {
@@ -272,6 +274,19 @@ vconn_get_ip(const struct vconn *vconn)
     return vconn->ip;
 }
 
+/* Returns true if, when 'vconn' is closed, it is possible to try to reconnect
+ * to it using the name that was originally used.  This is ordinarily the case.
+ *
+ * Returns false if reconnecting under the same name will never work in the way
+ * that you would expect.  This is the case if 'vconn' represents a "fd:N" type
+ * vconn; one can never connect to such a vconn more than once, because closing
+ * it closes the file descriptor. */
+bool
+vconn_is_reconnectable(const struct vconn *vconn)
+{
+    return vconn->reconnectable;
+}
+
 static void
 vcs_connecting(struct vconn *vconn) 
 {
@@ -893,7 +908,7 @@ make_echo_reply(const struct ofp_header *rq)
 
 void
 vconn_init(struct vconn *vconn, struct vconn_class *class, int connect_status,
-           uint32_t ip, const char *name)
+           uint32_t ip, const char *name, bool reconnectable)
 {
     vconn->class = class;
     vconn->state = (connect_status == EAGAIN ? VCS_CONNECTING
@@ -904,6 +919,7 @@ vconn_init(struct vconn *vconn, struct vconn_class *class, int connect_status,
     vconn->min_version = -1;
     vconn->ip = ip;
     vconn->name = xstrdup(name);
+    vconn->reconnectable = reconnectable;
 }
 
 void
index 6057c8a34034bc4066e985158c072182169d5ff0..3baaea6bc58679feddb13424956753b926b57841 100644 (file)
@@ -51,6 +51,7 @@ int vconn_open(const char *name, int min_version, struct vconn **);
 void vconn_close(struct vconn *);
 const char *vconn_get_name(const struct vconn *);
 uint32_t vconn_get_ip(const struct vconn *);
+bool vconn_is_reconnectable(const struct vconn *);
 int vconn_connect(struct vconn *);
 int vconn_recv(struct vconn *, struct ofpbuf **);
 int vconn_send(struct vconn *, struct ofpbuf *);
index 2f6a67666abdd3dc1566f9c01876e7480a92b9a4..58bd7d831cb763abbd38a5caab9464dfd4f692b3 100644 (file)
@@ -30,6 +30,7 @@ VLOG_MODULE(status)
 VLOG_MODULE(switch)
 VLOG_MODULE(terminal)
 VLOG_MODULE(socket_util)
+VLOG_MODULE(vconn_fd)
 VLOG_MODULE(vconn_netlink)
 VLOG_MODULE(vconn_tcp)
 VLOG_MODULE(vconn_ssl)