1 /* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
4 * We are making the OpenFlow specification and associated documentation
5 * (Software) available for public use and benefit with the expectation
6 * that others will use, modify and enhance the Software and contribute
7 * those enhancements back to the community. However, since we would
8 * like to make the Software available for broadest use, with as few
9 * restrictions as possible permission is hereby granted, free of
10 * charge, to any person obtaining a copy of this Software to deal in
11 * the Software under the copyrights without restriction, including
12 * without limitation the rights to use, copy, modify, merge, publish,
13 * distribute, sublicense, and/or sell copies of the Software, and to
14 * permit persons to whom the Software is furnished to do so, subject to
15 * the following conditions:
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 * The name and trademarks of copyright holder(s) may NOT be used in
30 * advertising or publicity pertaining to the Software or any
31 * derivatives without specific, written prior permission.
43 #include "command-line.h"
49 #include "vconn-ssl.h"
50 #include "vlog-socket.h"
52 #include "poll-loop.h"
56 #define THIS_MODULE VLM_secchan
58 static void parse_options(int argc, char *argv[]);
59 static void usage(void) NO_RETURN;
61 static struct vconn *listen_vconn = NULL;
70 struct half halves[2];
73 static struct list relays = LIST_INITIALIZER(&relays);
75 static void new_management_connection(const char *nl_name, struct vconn *new_remote);
76 static void relay_create(struct rconn *, struct rconn *);
77 static void relay_run(struct relay *);
78 static void relay_wait(struct relay *);
79 static void relay_destroy(struct relay *);
82 main(int argc, char *argv[])
87 set_program_name(argv[0]);
88 register_fault_handlers();
90 parse_options(argc, argv);
92 if (argc - optind != 2) {
94 "need exactly two non-option arguments; use --help for usage");
96 nl_name = argv[optind];
97 if (strncmp(nl_name, "nl:", 3)
98 || strlen(nl_name) < 4
99 || nl_name[strspn(nl_name + 3, "0123456789") + 3]) {
100 fatal(0, "%s: argument is not of the form \"nl:DP_ID\"", nl_name);
103 retval = vlog_server_listen(NULL, NULL);
105 fatal(retval, "Could not listen for vlog connections");
108 relay_create(rconn_new(argv[optind], 1), rconn_new(argv[optind + 1], 1));
113 LIST_FOR_EACH_SAFE (r, n, struct relay, node, &relays) {
117 struct vconn *new_remote;
119 retval = vconn_accept(listen_vconn, &new_remote);
121 if (retval != EAGAIN) {
122 VLOG_WARN("accept failed (%s)", strerror(retval));
127 new_management_connection(nl_name, new_remote);
131 /* Wait for something to happen. */
132 LIST_FOR_EACH (r, struct relay, node, &relays) {
136 vconn_accept_wait(listen_vconn);
145 new_management_connection(const char *nl_name, struct vconn *new_remote)
147 char *nl_name_without_subscription;
148 struct vconn *new_local;
149 struct rconn *r1, *r2;
152 /* nl:123 or nl:123:1 opens a netlink connection to local datapath 123. We
153 * only accept the former syntax in main().
155 * nl:123:0 opens a netlink connection to local datapath 123 without
156 * obtaining a subscription for ofp_packet_in or ofp_flow_expired
158 nl_name_without_subscription = xasprintf("%s:0", nl_name);
159 retval = vconn_open(nl_name_without_subscription, &new_local);
161 VLOG_ERR("could not connect to %s (%s)",
162 nl_name_without_subscription, strerror(retval));
163 vconn_close(new_remote);
166 free(nl_name_without_subscription);
168 /* Add it to the relay list. */
169 r1 = rconn_new_from_vconn(nl_name_without_subscription, 1, new_local);
170 r2 = rconn_new_from_vconn("passive", 1, new_remote);
171 relay_create(r1, r2);
175 relay_create(struct rconn *a, struct rconn *b)
180 r = xmalloc(sizeof *r);
181 for (i = 0; i < 2; i++) {
182 r->halves[i].rconn = i ? b : a;
183 r->halves[i].rxbuf = NULL;
185 list_push_back(&relays, &r->node);
189 relay_run(struct relay *r)
194 for (i = 0; i < 2; i++) {
195 rconn_run(r->halves[i].rconn);
198 /* Limit the number of iterations to prevent other tasks from starving. */
199 for (iteration = 0; iteration < 50; iteration++) {
200 bool progress = false;
201 for (i = 0; i < 2; i++) {
202 struct half *this = &r->halves[i];
203 struct half *peer = &r->halves[!i];
206 this->rxbuf = rconn_recv(this->rconn);
210 int retval = rconn_send(peer->rconn, this->rxbuf);
211 if (retval != EAGAIN) {
224 for (i = 0; i < 2; i++) {
225 struct half *this = &r->halves[i];
226 if (!rconn_is_alive(this->rconn)) {
234 relay_wait(struct relay *r)
238 for (i = 0; i < 2; i++) {
239 struct half *this = &r->halves[i];
241 rconn_run_wait(this->rconn);
243 rconn_recv_wait(this->rconn);
249 relay_destroy(struct relay *r)
253 list_remove(&r->node);
254 for (i = 0; i < 2; i++) {
255 struct half *this = &r->halves[i];
256 rconn_destroy(this->rconn);
257 buffer_delete(this->rxbuf);
263 parse_options(int argc, char *argv[])
265 static struct option long_options[] = {
266 {"listen", required_argument, 0, 'l'},
267 {"verbose", optional_argument, 0, 'v'},
268 {"help", no_argument, 0, 'h'},
269 {"version", no_argument, 0, 'V'},
271 {"private-key", required_argument, 0, 'p'},
272 {"certificate", required_argument, 0, 'c'},
273 {"ca-cert", required_argument, 0, 'C'},
277 char *short_options = long_options_to_short_options(long_options);
283 c = getopt_long(argc, argv, short_options, long_options, NULL);
291 fatal(0, "-l or --listen may be only specified once");
293 retval = vconn_open(optarg, &listen_vconn);
294 if (retval && retval != EAGAIN) {
295 fatal(retval, "opening %s", optarg);
297 if (!vconn_is_passive(listen_vconn)) {
298 fatal(0, "%s is not a passive vconn", optarg);
306 printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]);
310 vlog_set_verbosity(optarg);
315 vconn_ssl_set_private_key_file(optarg);
319 vconn_ssl_set_certificate_file(optarg);
323 vconn_ssl_set_ca_cert_file(optarg);
340 printf("%s: Secure Channel\n"
341 "usage: %s [OPTIONS] LOCAL REMOTE\n"
342 "\nRelays OpenFlow message between LOCAL and REMOTE datapaths.\n"
343 "LOCAL and REMOTE must each be one of the following:\n"
344 " tcp:HOST[:PORT] PORT (default: %d) on remote TCP HOST\n",
345 program_name, program_name, OFP_TCP_PORT);
347 printf(" nl:DP_IDX local datapath DP_IDX\n");
350 printf(" ssl:HOST[:PORT] SSL PORT (default: %d) on remote HOST\n"
351 "\nPKI configuration (required to use SSL):\n"
352 " -p, --private-key=FILE file with private key\n"
353 " -c, --certificate=FILE file with certificate for private key\n"
354 " -C, --ca-cert=FILE file with peer CA certificate\n",
357 printf("\nNetworking options:\n"
358 " -l, --listen=VCONN allow management connections on VCONN:\n"
359 " ptcp:[PORT] TCP PORT (default: %d)\n",
362 printf(" pssl:[PORT] SSL PORT (default: %d)\n",
365 printf("\nOther options:\n"
366 " -v, --verbose set maximum verbosity level\n"
367 " -h, --help display this help message\n"
368 " -V, --version display version information\n");