From: Ben Pfaff Date: Wed, 2 Apr 2008 17:55:17 +0000 (-0700) Subject: Rename controller_connection to rconn and use it in secchan also. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;ds=sidebyside;h=14da11884d45be826269fdebc548107a555dd6f0;p=openvswitch Rename controller_connection to rconn and use it in secchan also. Also, clean up code and add comments. --- diff --git a/include/Makefile.am b/include/Makefile.am index 409b2d63..0b7ddbe9 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -16,6 +16,7 @@ noinst_HEADERS = \ packets.h \ poll-loop.h \ queue.h \ + rconn.h \ socket-util.h \ util.h \ vconn.h \ diff --git a/include/rconn.h b/include/rconn.h new file mode 100644 index 00000000..4049e745 --- /dev/null +++ b/include/rconn.h @@ -0,0 +1,70 @@ +/* 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. + */ + +#ifndef RCONN_H +#define RCONN_H 1 + +#include "queue.h" +#include +#include + +/* A wrapper around vconn that provides queuing and optionally reliability. + * + * An rconn maintains a message transmission queue of bounded length specified + * by the caller. The rconn does not guarantee reliable delivery of + * queued messages: all queued messages are dropped when reconnection becomes + * necessary. + * + * An rconn optionally provides reliable communication, in this sense: the + * rconn will re-connect, with exponential backoff, when the underlying vconn + * disconnects. + */ + +struct vconn; + +struct rconn *rconn_new(const char *name, int txq_limit); +struct rconn *rconn_new_from_vconn(const char *name, int txq_limit, + struct vconn *); +void rconn_destroy(struct rconn *); + +void rconn_run(struct rconn *); +void rconn_run_wait(struct rconn *); +struct buffer *rconn_recv(struct rconn *); +void rconn_recv_wait(struct rconn *); +int rconn_send(struct rconn *, struct buffer *); +void rconn_send_wait(struct rconn *); + +const char *rconn_get_name(const struct rconn *); +bool rconn_is_alive(const struct rconn *); + +#endif /* rconn.h */ diff --git a/include/vlog.h b/include/vlog.h index 7d15ad28..01b2a851 100644 --- a/include/vlog.h +++ b/include/vlog.h @@ -63,7 +63,6 @@ enum vlog_facility vlog_get_facility_val(const char *name); #define VLOG_MODULES \ VLOG_MODULE(chain) \ VLOG_MODULE(controller) \ - VLOG_MODULE(controller_connection) \ VLOG_MODULE(ctlpath) \ VLOG_MODULE(datapath) \ VLOG_MODULE(dpif) \ @@ -74,6 +73,7 @@ enum vlog_facility vlog_get_facility_val(const char *name); VLOG_MODULE(netlink) \ VLOG_MODULE(poll_loop) \ VLOG_MODULE(secchan) \ + VLOG_MODULE(rconn) \ VLOG_MODULE(switch) \ VLOG_MODULE(socket_util) \ VLOG_MODULE(vconn_netlink) \ diff --git a/lib/Makefile.am b/lib/Makefile.am index fff0c7fc..c34cba43 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -14,6 +14,7 @@ libopenflow_la_SOURCES = \ ofp-print.c \ poll-loop.c \ queue.c \ + rconn.c \ socket-util.c \ util.c \ vconn-tcp.c \ diff --git a/lib/rconn.c b/lib/rconn.c new file mode 100644 index 00000000..f62ac61a --- /dev/null +++ b/lib/rconn.c @@ -0,0 +1,287 @@ +/* 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 "rconn.h" +#include +#include +#include +#include +#include "buffer.h" +#include "poll-loop.h" +#include "ofp-print.h" +#include "util.h" +#include "vconn.h" + +#define THIS_MODULE VLM_rconn +#include "vlog.h" + +/* A reliable connection to an OpenFlow switch or controller. + * + * See the large comment in rconn.h for more information. */ +struct rconn { + bool reliable; + char *name; + struct vconn *vconn; + bool connected; + struct queue txq; + int txq_limit; + time_t backoff_deadline; + int backoff; +}; + +static struct rconn *create_rconn(const char *name, int txq_limit, + struct vconn *); +static int try_send(struct rconn *); +static void disconnect(struct rconn *, int error); + +/* Creates and returns a new rconn that connects (and re-connects as necessary) + * to the vconn named 'name'. + * + * 'txq_limit' is the maximum length of the send queue, in packets. */ +struct rconn * +rconn_new(const char *name, int txq_limit) +{ + return create_rconn(name, txq_limit, NULL); +} + +/* Creates and returns a new rconn that is initially connected to 'vconn' and + * has the given 'name'. The rconn will not re-connect after the connection + * drops. + * + * 'txq_limit' is the maximum length of the send queue, in packets. */ +struct rconn * +rconn_new_from_vconn(const char *name, int txq_limit, struct vconn *vconn) +{ + assert(vconn != NULL); + return create_rconn(name, txq_limit, vconn); +} + +/* Disconnects 'rc' and frees the underlying storage. */ +void +rconn_destroy(struct rconn *rc) +{ + if (rc) { + free(rc->name); + vconn_close(rc->vconn); + queue_destroy(&rc->txq); + free(rc); + } +} + +/* Performs whatever activities are necessary to maintain 'rc': if 'rc' is + * disconnected, attempts to (re)connect, backing off as necessary; if 'rc' is + * connected, attempts to send packets in the send queue, if any. */ +void +rconn_run(struct rconn *rc) +{ + if (!rc->vconn) { + if (rc->reliable && time(0) >= rc->backoff_deadline) { + int retval; + + retval = vconn_open(rc->name, &rc->vconn); + if (!retval) { + rc->backoff_deadline = time(0) + rc->backoff; + rc->connected = false; + } else { + VLOG_WARN("%s: connection failed (%s)", + rc->name, strerror(retval)); + disconnect(rc, 0); + } + } + } else if (!rc->connected) { + int error = vconn_connect(rc->vconn); + if (!error) { + VLOG_WARN("%s: connected", rc->name); + if (vconn_is_passive(rc->vconn)) { + fatal(0, "%s: passive vconn not supported in switch", + rc->name); + } + rc->connected = true; + } else if (error != EAGAIN) { + VLOG_WARN("%s: connection failed (%s)", rc->name, strerror(error)); + disconnect(rc, 0); + } + } else { + while (rc->txq.n > 0) { + int error = try_send(rc); + if (error == EAGAIN) { + break; + } else if (error) { + disconnect(rc, error); + return; + } + } + } +} + +/* Causes the next call to poll_block() to wake up when rconn_run() should be + * called on 'rc'. */ +void +rconn_run_wait(struct rconn *rc) +{ + if (rc->vconn) { + if (rc->txq.n) { + vconn_wait(rc->vconn, WAIT_SEND); + } + } else { + poll_timer_wait((rc->backoff_deadline - time(0)) * 1000); + } +} + +/* Attempts to receive a packet from 'rc'. If successful, returns the packet; + * otherwise, returns a null pointer. The caller is responsible for freeing + * the packet (with buffer_delete()). */ +struct buffer * +rconn_recv(struct rconn *rc) +{ + if (rc->vconn && rc->connected) { + struct buffer *buffer; + int error = vconn_recv(rc->vconn, &buffer); + if (!error) { + return buffer; + } else if (error != EAGAIN) { + disconnect(rc, error); + } + } + return NULL; +} + +/* Causes the next call to poll_block() to wake up when a packet may be ready + * to be received by vconn_recv() on 'rc'. */ +void +rconn_recv_wait(struct rconn *rc) +{ + if (rc->vconn) { + vconn_wait(rc->vconn, WAIT_RECV); + } +} + +/* There is no rconn_send_wait() function: an rconn has a send queue that it + * takes care of sending if you call rconn_wait(), which will have the side + * effect of waking up poll_block(). */ +int +rconn_send(struct rconn *rc, struct buffer *b) +{ + if (rc->vconn) { + if (rc->txq.n < rc->txq_limit) { + queue_push_tail(&rc->txq, b); + if (rc->txq.n == 1) { + try_send(rc); + } + return 0; + } else { + return EAGAIN; + } + } else { + return ENOTCONN; + } +} + +/* Returns 'rc''s name (the 'name' argument passed to rconn_new()). */ +const char * +rconn_get_name(const struct rconn *rc) +{ + return rc->name; +} + +/* Returns true if 'rconn' is connected or in the process of reconnecting, + * false if 'rconn' is disconnected and will not be reconnected. */ +bool +rconn_is_alive(const struct rconn *rconn) +{ + return rconn->reliable || rconn->vconn; +} + +static struct rconn * +create_rconn(const char *name, int txq_limit, struct vconn *vconn) +{ + struct rconn *rc = xmalloc(sizeof *rc); + assert(txq_limit > 0); + rc->reliable = vconn == NULL; + rc->name = xstrdup(name); + rc->vconn = vconn; + queue_init(&rc->txq); + rc->txq_limit = txq_limit; + rc->backoff_deadline = 0; + rc->backoff = 0; + return rc; +} + +/* Tries to send a packet from 'rc''s send buffer. Returns 0 if successful, + * otherwise a positive errno value. */ +static int +try_send(struct rconn *rc) +{ + int retval = 0; + struct buffer *next = rc->txq.head->next; + retval = vconn_send(rc->vconn, rc->txq.head); + if (retval) { + return retval; + } + queue_advance_head(&rc->txq, next); + return 0; +} + +/* Disconnects 'rc'. 'error' is used only for logging purposes. If it is + * nonzero, then it should be EOF to indicate the connection was closed by the + * peer in a normal fashion or a positive errno value. */ +static void +disconnect(struct rconn *rc, int error) +{ + time_t now = time(0); + + if (rc->vconn) { + if (error > 0) { + VLOG_WARN("%s: connection dropped (%s)", + rc->name, strerror(error)); + } else if (error == EOF) { + if (rc->reliable) { + VLOG_WARN("%s: connection closed", rc->name); + } + } else { + VLOG_WARN("%s: connection dropped", rc->name); + } + vconn_close(rc->vconn); + rc->vconn = NULL; + queue_clear(&rc->txq); + } + + if (now >= rc->backoff_deadline) { + rc->backoff = 1; + } else { + rc->backoff = MIN(60, MAX(1, 2 * rc->backoff)); + VLOG_WARN("%s: waiting %d seconds before reconnect\n", + rc->name, rc->backoff); + } + rc->backoff_deadline = now + rc->backoff; +} diff --git a/man/man8/secchan.8 b/man/man8/secchan.8 index 3f783319..b1eac3a9 100644 --- a/man/man8/secchan.8 +++ b/man/man8/secchan.8 @@ -24,11 +24,6 @@ proceeds to forward packets from one endpoint to the other. .BR \-h ", " \-\^\-help Prints a brief help message to the console. -.TP -.BR \-u ", " \-\^\-unreliable -Do not attempt to reconnect the channel if a connection drops. By -default, \fBsecchan\fR attempts to reconnect. - .TP .BR \-v ", " \-\^\-verbose Prints debug messages to the console. diff --git a/man/man8/switch.8 b/man/man8/switch.8 index 78f9e571..51638a36 100644 --- a/man/man8/switch.8 +++ b/man/man8/switch.8 @@ -76,11 +76,6 @@ the switch is connected to a trustworthy controller. .BR \-h ", " \-\^\-help Prints a brief help message to the console. -.TP -.BR \-u ", " \-\^\-unreliable -Do not attempt to reconnect the channel if a connection drops. By -default, \fBsecchan\fR attempts to reconnect. - .TP .BR \-v ", " \-\^\-verbose Prints debug messages to the console. diff --git a/secchan/secchan.c b/secchan/secchan.c index 5d693781..e2486936 100644 --- a/secchan/secchan.c +++ b/secchan/secchan.c @@ -44,8 +44,8 @@ #include "compiler.h" #include "fault.h" #include "util.h" +#include "rconn.h" #include "vconn-ssl.h" -#include "vconn.h" #include "vlog-socket.h" #include "openflow.h" #include "poll-loop.h" @@ -58,19 +58,14 @@ static void usage(void) NO_RETURN; static bool reliable = true; -struct half { - const char *name; - struct vconn *vconn; - struct buffer *rxbuf; - time_t backoff_deadline; - int backoff; -}; - -static void reconnect(struct half *); - int main(int argc, char *argv[]) { + struct half { + struct rconn *rconn; + struct buffer *rxbuf; + }; + struct half halves[2]; int retval; int i; @@ -90,17 +85,18 @@ main(int argc, char *argv[]) } for (i = 0; i < 2; i++) { - halves[i].name = argv[optind + i]; - halves[i].vconn = NULL; + halves[i].rconn = rconn_new(argv[optind + i], 1); halves[i].rxbuf = NULL; - halves[i].backoff_deadline = 0; - halves[i].backoff = 1; - reconnect(&halves[i]); } for (;;) { /* Do some work. Limit the number of iterations so that callbacks * registered with the poll loop don't starve. */ int iteration; + + for (i = 0; i < 2; i++) { + rconn_run(halves[i].rconn); + } + for (iteration = 0; iteration < 50; iteration++) { bool progress = false; for (i = 0; i < 2; i++) { @@ -108,30 +104,16 @@ main(int argc, char *argv[]) struct half *peer = &halves[!i]; if (!this->rxbuf) { - retval = vconn_recv(this->vconn, &this->rxbuf); - if (retval && retval != EAGAIN) { - if (retval == EOF) { - VLOG_DBG("%s: connection closed by remote host", - this->name); - } else { - VLOG_DBG("%s: recv: closing connection: %s", - this->name, strerror(retval)); - } - reconnect(this); - break; - } + this->rxbuf = rconn_recv(this->rconn); } if (this->rxbuf) { - retval = vconn_send(peer->vconn, this->rxbuf); - if (!retval) { + retval = rconn_send(peer->rconn, this->rxbuf); + if (retval != EAGAIN) { this->rxbuf = NULL; - progress = true; - } else if (retval != EAGAIN) { - VLOG_DBG("%s: send: closing connection: %s", - peer->name, strerror(retval)); - reconnect(peer); - break; + if (!retval) { + progress = true; + } } } } @@ -143,11 +125,10 @@ main(int argc, char *argv[]) /* Wait for something to happen. */ for (i = 0; i < 2; i++) { struct half *this = &halves[i]; - struct half *peer = &halves[!i]; + + rconn_run_wait(this->rconn); if (!this->rxbuf) { - vconn_recv_wait(this->vconn); - } else { - vconn_send_wait(peer->vconn); + rconn_recv_wait(this->rconn); } } poll_block(); @@ -156,62 +137,10 @@ main(int argc, char *argv[]) return 0; } -static void -reconnect(struct half *this) -{ - if (this->vconn != NULL) { - if (!reliable) { - fatal(0, "%s: connection dropped", this->name); - } - - VLOG_WARN("%s: connection dropped, reconnecting", this->name); - vconn_close(this->vconn); - this->vconn = NULL; - buffer_delete(this->rxbuf); - this->rxbuf = NULL; - } - - for (;;) { - time_t now = time(0); - int retval; - - if (now >= this->backoff_deadline) { - this->backoff = 1; - } else { - this->backoff *= 2; - if (this->backoff > 60) { - this->backoff = 60; - } - VLOG_WARN("%s: waiting %d seconds before reconnect\n", - this->name, (int) (this->backoff_deadline - now)); - poll_timer_wait((this->backoff_deadline - now) * 1000); - poll_block(); - } - - retval = vconn_open_block(this->name, &this->vconn); - if (!retval) { - VLOG_WARN("%s: connected", this->name); - if (vconn_is_passive(this->vconn)) { - fatal(0, "%s: passive vconn not supported in control path", - this->name); - } - this->backoff_deadline = now + this->backoff; - return; - } - - if (!reliable) { - fatal(0, "%s: connection failed", this->name); - } - VLOG_WARN("%s: connection failed (%s)", this->name, strerror(retval)); - this->backoff_deadline = time(0) + this->backoff; - } -} - static void parse_options(int argc, char *argv[]) { static struct option long_options[] = { - {"unreliable", no_argument, 0, 'u'}, {"verbose", optional_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, @@ -234,10 +163,6 @@ parse_options(int argc, char *argv[]) } switch (c) { - case 'u': - reliable = false; - break; - case 'h': usage(); @@ -293,9 +218,7 @@ usage(void) " -C, --ca-cert=FILE file with peer CA certificate\n", OFP_SSL_PORT); #endif - printf("\nNetworking options:\n" - " -u, --unreliable do not reconnect after connections drop\n" - "\nOther options:\n" + printf("\nOther options:\n" " -v, --verbose set maximum verbosity level\n" " -h, --help display this help message\n" " -V, --version display version information\n"); diff --git a/switch/Makefile.am b/switch/Makefile.am index 24c23891..eb9931b0 100644 --- a/switch/Makefile.am +++ b/switch/Makefile.am @@ -5,8 +5,6 @@ bin_PROGRAMS = switch switch_SOURCES = \ chain.c \ chain.h \ - controller.c \ - controller.h \ crc32.c \ crc32.h \ datapath.c \ diff --git a/switch/controller.c b/switch/controller.c deleted file mode 100644 index d8152311..00000000 --- a/switch/controller.c +++ /dev/null @@ -1,208 +0,0 @@ -/* 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 "controller.h" -#include -#include -#include "buffer.h" -#include "poll-loop.h" -#include "ofp-print.h" -#include "util.h" -#include "vconn.h" - -#define THIS_MODULE VLM_controller_connection -#include "vlog.h" - -struct controller_connection { - bool reliable; - const char *name; - struct vconn *vconn; - bool connected; - struct queue txq; - time_t backoff_deadline; - int backoff; -}; - -struct controller_connection * -controller_new(const char *name, bool reliable) -{ - struct controller_connection *cc = xmalloc(sizeof *cc); - cc->reliable = reliable; - cc->name = name; - cc->vconn = NULL; - queue_init(&cc->txq); - cc->backoff_deadline = 0; - cc->backoff = 0; - return cc; -} - -static int -try_send(struct controller_connection *cc) -{ - int retval = 0; - struct buffer *next = cc->txq.head->next; - retval = vconn_send(cc->vconn, cc->txq.head); - if (retval) { - return retval; - } - queue_advance_head(&cc->txq, next); - return 0; -} - -void -controller_run(struct controller_connection *cc) -{ - if (!cc->vconn) { - if (time(0) >= cc->backoff_deadline) { - int retval; - - retval = vconn_open(cc->name, &cc->vconn); - if (!retval) { - cc->backoff_deadline = time(0) + cc->backoff; - cc->connected = false; - } else { - VLOG_WARN("%s: connection failed (%s)", - cc->name, strerror(retval)); - controller_disconnect(cc, 0); - } - } - } else if (!cc->connected) { - int error = vconn_connect(cc->vconn); - if (!error) { - VLOG_WARN("%s: connected", cc->name); - if (vconn_is_passive(cc->vconn)) { - fatal(0, "%s: passive vconn not supported in switch", - cc->name); - } - cc->connected = true; - } else if (error != EAGAIN) { - VLOG_WARN("%s: connection failed (%s)", - cc->name, strerror(error)); - controller_disconnect(cc, 0); - } - } else { - while (cc->txq.n > 0) { - int error = try_send(cc); - if (error == EAGAIN) { - break; - } else if (error) { - controller_disconnect(cc, error); - return; - } - } - } -} - -void -controller_run_wait(struct controller_connection *cc) -{ - if (cc->vconn) { - if (cc->txq.n) { - vconn_wait(cc->vconn, WAIT_SEND); - } - } else { - poll_timer_wait((cc->backoff_deadline - time(0)) * 1000); - } -} - -void -controller_disconnect(struct controller_connection *cc, int error) -{ - time_t now = time(0); - - if (cc->vconn) { - if (!cc->reliable) { - fatal(0, "%s: connection dropped", cc->name); - } - - if (error > 0) { - VLOG_WARN("%s: connection dropped (%s)", - cc->name, strerror(error)); - } else if (error == EOF) { - VLOG_WARN("%s: connection closed", cc->name); - } else { - VLOG_WARN("%s: connection dropped", cc->name); - } - vconn_close(cc->vconn); - cc->vconn = NULL; - queue_clear(&cc->txq); - } - - if (now >= cc->backoff_deadline) { - cc->backoff = 1; - } else { - cc->backoff = MIN(60, MAX(1, 2 * cc->backoff)); - VLOG_WARN("%s: waiting %d seconds before reconnect\n", - cc->name, cc->backoff); - } - cc->backoff_deadline = now + cc->backoff; -} - -struct buffer * -controller_recv(struct controller_connection *cc) -{ - if (cc->vconn && cc->connected) { - struct buffer *buffer; - int error = vconn_recv(cc->vconn, &buffer); - if (!error) { - return buffer; - } else if (error != EAGAIN) { - controller_disconnect(cc, error); - } - } - return NULL; -} - -void -controller_recv_wait(struct controller_connection *cc) -{ - if (cc->vconn) { - vconn_wait(cc->vconn, WAIT_RECV); - } -} - -void -controller_send(struct controller_connection *cc, struct buffer *b) -{ - if (cc->vconn) { - if (cc->txq.n < 128) { - queue_push_tail(&cc->txq, b); - if (cc->txq.n == 1) { - try_send(cc); - } - } else { - VLOG_WARN("%s: controller queue overflow", cc->name); - buffer_delete(b); - } - } -} diff --git a/switch/controller.h b/switch/controller.h deleted file mode 100644 index 6c38dd11..00000000 --- a/switch/controller.h +++ /dev/null @@ -1,50 +0,0 @@ -/* 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. - */ - -#ifndef CONTROLLER_H -#define CONTROLLER_H 1 - -#include "queue.h" -#include -#include - -struct controller_connection *controller_new(const char *name, bool reliable); -void controller_run(struct controller_connection *); -void controller_run_wait(struct controller_connection *); -void controller_connect(struct controller_connection *); -void controller_disconnect(struct controller_connection *, int error); -struct buffer *controller_recv(struct controller_connection *); -void controller_recv_wait(struct controller_connection *); -void controller_send(struct controller_connection *, struct buffer *); - -#endif /* controller.h */ diff --git a/switch/datapath.c b/switch/datapath.c index 40753ae4..b59e789b 100644 --- a/switch/datapath.c +++ b/switch/datapath.c @@ -39,11 +39,11 @@ #include #include "buffer.h" #include "chain.h" -#include "controller.h" #include "flow.h" #include "netdev.h" #include "packets.h" #include "poll-loop.h" +#include "rconn.h" #include "table.h" #include "xtoxll.h" @@ -73,7 +73,7 @@ struct sw_port { }; struct datapath { - struct controller_connection *cc; + struct rconn *rconn; time_t last_timeout; @@ -157,7 +157,7 @@ gen_datapath_id(void) } int -dp_new(struct datapath **dp_, uint64_t dpid, struct controller_connection *cc) +dp_new(struct datapath **dp_, uint64_t dpid, struct rconn *rconn) { struct datapath *dp; @@ -167,7 +167,7 @@ dp_new(struct datapath **dp_, uint64_t dpid, struct controller_connection *cc) } dp->last_timeout = time(0); - dp->cc = cc; + dp->rconn = rconn; dp->id = dpid <= UINT64_C(0xffffffffffff) ? dpid : gen_datapath_id(); dp->chain = chain_create(); if (!dp->chain) { @@ -262,7 +262,7 @@ dp_run(struct datapath *dp) /* Process a number of commands from the controller, but cap it at a * reasonable number so that other processing doesn't starve. */ for (i = 0; i < 50; i++) { - struct buffer *buffer = controller_recv(dp->cc); + struct buffer *buffer = rconn_recv(dp->rconn); if (!buffer) { break; } @@ -270,7 +270,7 @@ dp_run(struct datapath *dp) buffer_delete(buffer); } - controller_run(dp->cc); + rconn_run(dp->rconn); } void @@ -281,7 +281,7 @@ dp_wait(struct datapath *dp) LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) { netdev_recv_wait(p->netdev); } - controller_recv_wait(dp->cc); + rconn_recv_wait(dp->rconn); } /* Delete 'p' from switch. */ @@ -397,7 +397,7 @@ dp_output_control(struct datapath *dp, struct buffer *buffer, int in_port, opi->in_port = htons(in_port); opi->reason = reason; opi->pad = 0; - controller_send(dp->cc, buffer); + rconn_send(dp->rconn, buffer); } static void fill_port_desc(struct datapath *dp, struct sw_port *p, @@ -443,7 +443,7 @@ dp_send_hello(struct datapath *dp) } odh = buffer_at_assert(buffer, 0, sizeof *odh); odh->header.length = htons(buffer->size); - controller_send(dp->cc, buffer); + rconn_send(dp->rconn, buffer); } void @@ -474,7 +474,7 @@ send_port_status(struct sw_port *p, uint8_t status) ops->header.xid = htonl(0); ops->reason = status; fill_port_desc(p->dp, p, &ops->desc); - controller_send(p->dp->cc, buffer); + rconn_send(p->dp->rconn, buffer); } void @@ -492,7 +492,7 @@ send_flow_expired(struct datapath *dp, struct sw_flow *flow) ofe->duration = htonl(flow->timeout - flow->max_idle - flow->created); ofe->packet_count = htonll(flow->packet_count); ofe->byte_count = htonll(flow->byte_count); - controller_send(dp->cc, buffer); + rconn_send(dp->rconn, buffer); } /* 'buffer' was received on 'in_port', a physical switch port between 0 and diff --git a/switch/datapath.h b/switch/datapath.h index 6d52360d..b30de513 100644 --- a/switch/datapath.h +++ b/switch/datapath.h @@ -43,9 +43,9 @@ #include "list.h" struct datapath; -struct controller_connection; +struct rconn; -int dp_new(struct datapath **, uint64_t dpid, struct controller_connection *); +int dp_new(struct datapath **, uint64_t dpid, struct rconn *); int dp_add_port(struct datapath *, const char *netdev); void dp_run(struct datapath *); void dp_wait(struct datapath *); diff --git a/switch/switch.c b/switch/switch.c index e489b9fa..313c75f1 100644 --- a/switch/switch.c +++ b/switch/switch.c @@ -38,13 +38,13 @@ #include #include "command-line.h" -#include "controller.h" #include "datapath.h" #include "fault.h" #include "openflow.h" #include "poll-loop.h" #include "queue.h" #include "util.h" +#include "rconn.h" #include "vconn.h" #include "vconn-ssl.h" #include "vlog-socket.h" @@ -55,7 +55,6 @@ static void parse_options(int argc, char *argv[]); static void usage(void) NO_RETURN; -static bool reliable = true; static struct datapath *dp; static uint64_t dpid = UINT64_MAX; static char *port_list; @@ -65,7 +64,6 @@ static void add_ports(struct datapath *dp, char *port_list); int main(int argc, char *argv[]) { - struct controller_connection *cc; int error; set_program_name(argv[0]); @@ -77,8 +75,7 @@ main(int argc, char *argv[]) fatal(0, "missing controller argument; use --help for usage"); } - cc = controller_new(argv[optind], reliable); - error = dp_new(&dp, dpid, cc); + error = dp_new(&dp, dpid, rconn_new(argv[optind], 128)); if (error) { fatal(error, "could not create datapath"); } @@ -123,7 +120,6 @@ parse_options(int argc, char *argv[]) { static struct option long_options[] = { {"interfaces", required_argument, 0, 'i'}, - {"unreliable", no_argument, 0, 'u'}, {"datapath-id", required_argument, 0, 'd'}, {"verbose", optional_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, @@ -147,10 +143,6 @@ parse_options(int argc, char *argv[]) } switch (c) { - case 'u': - reliable = false; - break; - case 'd': if (strlen(optarg) != 12 || strspn(optarg, "0123456789abcdefABCDEF") != 12) { @@ -227,7 +219,6 @@ usage(void) " add specified initial switch ports\n" " -d, --datapath-id=ID Use ID as the OpenFlow switch ID\n" " (ID must consist of 12 hex digits)\n" - " -u, --unreliable do not reconnect to controller\n" " -v, --verbose set maximum verbosity level\n" " -h, --help display this help message\n" " -V, --version display version information\n");