From: Ben Pfaff Date: Wed, 31 Dec 2008 00:02:17 +0000 (-0800) Subject: vswitchd: Add support for remote controller. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fde04fa3da26d5081f897de31248bb79f57c2019;p=openvswitch vswitchd: Add support for remote controller. --- diff --git a/lib/svec.c b/lib/svec.c index 59d806cf..3a6f53de 100644 --- a/lib/svec.c +++ b/lib/svec.c @@ -34,10 +34,15 @@ #include #include "svec.h" #include +#include #include #include +#include "dynamic-string.h" #include "util.h" +#define THIS_MODULE VLM_svec +#include "vlog.h" + void svec_init(struct svec *svec) { @@ -86,6 +91,15 @@ svec_add_nocopy(struct svec *svec, char *name) svec->names[svec->n++] = name; } +void +svec_append(struct svec *svec, const struct svec *other) +{ + size_t i; + for (i = 0; i < other->n; i++) { + svec_add(svec, other->names[i]); + } +} + void svec_terminate(struct svec *svec) { @@ -216,3 +230,49 @@ svec_print(const struct svec *svec, const char *title) printf("\"%s\"\n", svec->names[i]); } } + +/* Breaks 'words' into words at white space, respecting shell-like quoting + * conventions, and appends the words to 'svec'. */ +void +svec_parse_words(struct svec *svec, const char *words) +{ + struct ds word = DS_EMPTY_INITIALIZER; + const char *p, *q; + + for (p = words; *p != '\0'; p = q) { + int quote = 0; + + while (isspace((unsigned char) *p)) { + p++; + } + if (*p == '\0') { + break; + } + + ds_clear(&word); + for (q = p; *q != '\0'; q++) { + if (*q == quote) { + quote = 0; + } else if (*q == '\'' || *q == '"') { + quote = *q; + } else if (*q == '\\' && (!quote || quote == '"')) { + q++; + if (*q == '\0') { + VLOG_WARN("%s: ends in trailing backslash", words); + break; + } + ds_put_char(&word, *q); + } else if (isspace((unsigned char) *q) && !quote) { + q++; + break; + } else { + ds_put_char(&word, *q); + } + } + svec_add(svec, ds_cstr(&word)); + if (quote) { + VLOG_WARN("%s: word ends inside quoted string", words); + } + } + ds_destroy(&word); +} diff --git a/lib/svec.h b/lib/svec.h index ac99a837..2215c3cc 100644 --- a/lib/svec.h +++ b/lib/svec.h @@ -50,7 +50,7 @@ void svec_destroy(struct svec *); void svec_clear(struct svec *); void svec_add(struct svec *, const char *); void svec_add_nocopy(struct svec *, char *); -void svec_merge(struct svec *, const struct svec *); +void svec_append(struct svec *, const struct svec *); void svec_terminate(struct svec *); void svec_sort(struct svec *); void svec_unique(struct svec *); @@ -60,5 +60,6 @@ bool svec_contains(const struct svec *, const char *); bool svec_is_sorted(const struct svec *); void svec_swap(struct svec *a, struct svec *b); void svec_print(const struct svec *svec, const char *title); +void svec_parse_words(struct svec *svec, const char *words); #endif /* svec.h */ diff --git a/lib/vlog-modules.def b/lib/vlog-modules.def index 2a787184..45287585 100644 --- a/lib/vlog-modules.def +++ b/lib/vlog-modules.def @@ -32,6 +32,7 @@ VLOG_MODULE(stp) VLOG_MODULE(stp_secchan) VLOG_MODULE(stats) VLOG_MODULE(status) +VLOG_MODULE(svec) VLOG_MODULE(switch) VLOG_MODULE(terminal) VLOG_MODULE(socket_util) diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index fc733536..fa76d3e0 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -119,6 +119,12 @@ struct bridge { bool sent_config_request; /* Successfully sent config request? */ bool sent_features_request; /* Successfully sent features request? */ + /* Support for remote controllers. */ + char *controller; /* NULL if there is no remote controller; + * "discover" to do controller discovery; + * otherwise a vconn name. */ + struct svec secchan_opts; /* Additional options for secchan. */ + /* Secure channel. */ enum { SC_UNSTARTED, /* Not yet started. */ @@ -341,13 +347,17 @@ bridge_wait(void) struct bridge *br; LIST_FOR_EACH (br, struct bridge, node, &all_bridges) { + if (br->secchan) { + process_wait(br->secchan); + } + if (br->controller) { + continue; + } + rconn_run_wait(br->rconn); if (!bridge_is_backlogged(br)) { rconn_recv_wait(br->rconn); } - if (br->secchan) { - process_wait(br->secchan); - } if (br->ml) { mac_learning_wait(br->ml); } @@ -392,6 +402,8 @@ bridge_create(const char *name) br->sent_config_request = false; br->sent_features_request = false; + svec_init(&br->secchan_opts); + br->sc_state = SC_UNSTARTED; br->sc_retries = 0; br->secchan = NULL; @@ -437,6 +449,15 @@ log_secchan_died(enum vlog_level level, struct bridge *br, bool expected) free(status); } +static void +kill_secchan(struct bridge *br) +{ + if (br->sc_state == SC_RUNNING) { + process_kill(br->secchan, SIGTERM); + br->sc_state = SC_DYING; + } +} + static void run_secchan(struct bridge *br) { @@ -452,8 +473,7 @@ run_secchan(struct bridge *br) } else if (!rconn_is_alive(br->rconn)) { VLOG_ERR("%s: connection to secchan closed unexpectedly, " "killing secchan", br->name); - process_kill(br->secchan, SIGTERM); - br->sc_state = SC_DYING; + kill_secchan(br); } break; @@ -511,9 +531,11 @@ start_secchan(struct bridge *br) /* Assemble command-line arguments. */ svec_init(&argv); svec_add(&argv, "secchan"); - svec_add(&argv, "--out-of-band"); + if (!br->controller) { + svec_add(&argv, "--out-of-band"); + svec_add(&argv, "--max-backoff=1"); + } svec_add(&argv, "--fail=closed"); - svec_add(&argv, "--max-backoff=1"); svec_add(&argv, "--no-stp"); if (!stat(ofp_rundir, &s)) { svec_add_nocopy(&argv, @@ -525,8 +547,15 @@ start_secchan(struct bridge *br) "%d{%b %d %H:%M:%S}", br->dp_idx, "%c|%p|%m")); + svec_append(&argv, &br->secchan_opts); svec_add_nocopy(&argv, xasprintf("nl:%d", br->dp_idx)); - svec_add_nocopy(&argv, xasprintf("fd:%d", sockets[1])); + if (br->controller) { + if (strcmp(br->controller, "discover")) { + svec_add(&argv, br->controller); + } + } else { + svec_add_nocopy(&argv, xasprintf("fd:%d", sockets[1])); + } svec_terminate(&argv); /* Start secchan. */ @@ -577,6 +606,8 @@ bridge_destroy(struct bridge *br) for (i = 0; i < br->n_ports; i++) { port_destroy(br->ports[i]); } + free(br->controller); + svec_destroy(&br->secchan_opts); ft_destroy(br->ft); stats_request_destroy(br->flow_rq); stats_mgr_destroy(br->stats_mgr); @@ -651,6 +682,11 @@ bridge_run_one(struct bridge *br) { int iteration; + if (br->controller) { + run_secchan(br); + return; + } + rconn_run(br->rconn); if (rconn_is_connected(br->rconn)) { @@ -702,6 +738,8 @@ static void bridge_reconfigure_one(struct bridge *br) { struct svec old_ports, new_ports; + const char *controller; + char *ctl; size_t i; /* Collect old and new ports. */ @@ -735,6 +773,30 @@ bridge_reconfigure_one(struct bridge *br) port_reconfigure(br->ports[i]); } + /* Configure remote controller. */ + controller = cfg_get_string(0, "bridge.%s.controller", br->name); + ctl = controller ? xstrdup(controller) : NULL; + if ((ctl == NULL) != (br->controller == NULL) + || (ctl && br->controller && strcmp(ctl, br->controller))) { + br->sc_retries = 0; + kill_secchan(br); + } + free(br->controller); + br->controller = ctl; + + /* Allow arbitrary secchan options if a remote controller is configured. */ + svec_clear(&br->secchan_opts); + if (ctl) { + for (i = 0; ; i++) { + const char *opt; + opt = cfg_get_string(i, "bridge.%s.secchan.options", br->name); + if (!opt) { + break; + } + svec_parse_words(&br->secchan_opts, opt); + } + } + /* Revive secchan if it's dead. */ if (br->sc_state == SC_DEAD) { br->sc_retries = 0; diff --git a/vswitchd/vswitchd.conf.5 b/vswitchd/vswitchd.conf.5 index f3f4fb18..b63451a6 100644 --- a/vswitchd/vswitchd.conf.5 +++ b/vswitchd/vswitchd.conf.5 @@ -135,6 +135,47 @@ with physical network devices \fBeth2\fR and \fBeth3\fR: .fi .RE +.SS "OpenFlow controller connectivity" +By default, \fBvswitchd\fR performs all configured bridging and +switching locally. It can also be configured to connect a given +bridge to an external OpenFlow controller, such as NOX, by setting +\fBbridge.\fIname\fB.controller\fR to one of the following forms: +. +.TP +\fBdiscover\fR +Use controller discovery to find the local OpenFlow controller. +Refer to \fBsecchan\fR(8) for information on how to configure a DHCP +server to support controller discovery. +. +.TP +\fBssl:\fIhost\fR[\fB:\fIport\fR] +The specified SSL \fIport\fR (default: 6633) on the given remote +\fIhost\fR. The \fB--private-key\fR, \fB--certificate\fR, and +\fB--ca-cert\fR options are mandatory when this form is used. +. +.TP +\fBtcp:\fIhost\fR[\fB:\fIport\fR] +The specified TCP \fIport\fR (default: 6633) on the given remote +\fIhost\fR. +. +.TP +\fBunix:\fIfile\fR +The Unix domain server socket named \fIfile\fR. +.PP +When an external controller is configured, +\fBbridge.\fIname\fB.secchan.options\fR may be used to pass arbitrary +additional options to \fBsecchan\fR. Each value for this option is +broken into words at white space, which are then passed as individual +arguments on \fBsecchan\fR's command line. Single or double quotes +may be used to prevent word-splitting; outside of single quotes, a +backslash quotes the following single character. +.PP +If an external controller is configured, and in-band control is used, +but not controller discovery (see \fBsecchan\fR(8) for more +information on this terminology), the local bridge port must +configured with an IP address by some entity outside \fBvswitch\fR, +which will not itself configure an IP address on it. +.PP .SH "SEE ALSO" .BR vswitchd (8).