From: Ben Pfaff Date: Wed, 17 Dec 2008 00:57:40 +0000 (-0800) Subject: Add new "fd" vconn, which takes a file descriptor number as argument. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0a14b62251bb21b76f71ee512958ee32627da2d5;p=openvswitch Add new "fd" vconn, which takes a file descriptor number as argument. 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. --- diff --git a/lib/automake.mk b/lib/automake.mk index 6b2af618..8f2c09f8 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -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 \ diff --git a/lib/rconn.c b/lib/rconn.c index ba606fb5..086cf7d9 100644 --- a/lib/rconn.c +++ b/lib/rconn.c @@ -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 index 00000000..ccc67685 --- /dev/null +++ b/lib/vconn-fd.c @@ -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 +#include "vconn.h" +#include +#include +#include +#include +#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 */ +}; diff --git a/lib/vconn-netlink.c b/lib/vconn-netlink.c index f7b86777..91faa713 100644 --- a/lib/vconn-netlink.c +++ b/lib/vconn-netlink.c @@ -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) { diff --git a/lib/vconn-provider.h b/lib/vconn-provider.h index cf033afc..caf739b2 100644 --- a/lib/vconn-provider.h +++ b/lib/vconn-provider.h @@ -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; diff --git a/lib/vconn-ssl.c b/lib/vconn-ssl.c index 6d24e277..a00906c9 100644 --- a/lib/vconn-ssl.c +++ b/lib/vconn-ssl.c @@ -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; diff --git a/lib/vconn-stream.c b/lib/vconn-stream.c index 0b852611..cdbea1fb 100644 --- a/lib/vconn-stream.c +++ b/lib/vconn-stream.c @@ -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; diff --git a/lib/vconn-stream.h b/lib/vconn-stream.h index a9b1e7b3..7238a1f1 100644 --- a/lib/vconn-stream.h +++ b/lib/vconn-stream.h @@ -34,6 +34,7 @@ #ifndef VCONN_STREAM_H #define VCONN_STREAM_H 1 +#include #include #include @@ -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 **), diff --git a/lib/vconn-tcp.c b/lib/vconn-tcp.c index 79d83322..4049f00c 100644 --- a/lib/vconn-tcp.c +++ b/lib/vconn-tcp.c @@ -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 diff --git a/lib/vconn-unix.c b/lib/vconn-unix.c index b1a7d8a7..48c27470 100644 --- a/lib/vconn-unix.c +++ b/lib/vconn-unix.c @@ -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 = { diff --git a/lib/vconn.c b/lib/vconn.c index e630258b..6b0bc71a 100644 --- a/lib/vconn.c +++ b/lib/vconn.c @@ -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 diff --git a/lib/vconn.h b/lib/vconn.h index 6057c8a3..3baaea6b 100644 --- a/lib/vconn.h +++ b/lib/vconn.h @@ -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 *); diff --git a/lib/vlog-modules.def b/lib/vlog-modules.def index 2f6a6766..58bd7d83 100644 --- a/lib/vlog-modules.def +++ b/lib/vlog-modules.def @@ -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)