Fix arguments to printf in usage message.
[openvswitch] / secchan / secchan.c
index b8a4c4c307c51134a8802a607f056d7727a5ff6e..f50b3ac52a586b60f03d35fdddf49e5b35f290ab 100644 (file)
@@ -24,6 +24,7 @@
 #include <poll.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
 #include <unistd.h>
 
 #include "buffer.h"
@@ -31,6 +32,7 @@
 #include "compiler.h"
 #include "fault.h"
 #include "util.h"
+#include "vconn-ssl.h"
 #include "vconn.h"
 #include "vlog-socket.h"
 #include "openflow.h"
@@ -48,6 +50,8 @@ struct half {
     struct vconn *vconn;
     struct pollfd *pollfd;
     struct buffer *rxbuf;
+    time_t backoff_deadline;
+    int backoff;
 };
 
 static void reconnect(struct half *);
@@ -80,10 +84,15 @@ main(int argc, char *argv[])
         halves[i].vconn = NULL;
         halves[i].pollfd = &pollfds[i];
         halves[i].rxbuf = NULL;
+        halves[i].backoff_deadline = 0;
+        halves[i].backoff = 1;
         reconnect(&halves[i]);
     }
     for (;;) {
+        size_t n_ready;
+        
         /* Wait until there's something to do. */
+        n_ready = 0;
         for (i = 0; i < 2; i++) {
             struct half *this = &halves[i];
             struct half *peer = &halves[!i];
@@ -96,16 +105,17 @@ main(int argc, char *argv[])
             }
             this->pollfd->fd = -1;
             this->pollfd->events = 0;
-            vconn_prepoll(this->vconn, want, this->pollfd);
+            n_ready += vconn_prepoll(this->vconn, want, this->pollfd);
         }
         if (vlog_server) {
             pollfds[2].fd = vlog_server_get_fd(vlog_server);
             pollfds[2].events = POLLIN;
         }
         do {
-            retval = poll(pollfds, 2 + (vlog_server != NULL), -1);
+            retval = poll(pollfds, 2 + (vlog_server != NULL),
+                          n_ready ? 0 : -1);
         } while (retval < 0 && errno == EINTR);
-        if (retval <= 0) {
+        if (retval < 0 || (retval == 0 && !n_ready)) {
             fatal(retval < 0 ? errno : 0, "poll");
         }
 
@@ -156,8 +166,6 @@ main(int argc, char *argv[])
 static void
 reconnect(struct half *this) 
 {
-    int backoff;
-    
     if (this->vconn != NULL) {
         if (!reliable) {
             fatal(0, "%s: connection dropped", this->name);
@@ -171,23 +179,38 @@ reconnect(struct half *this)
     }
     this->pollfd->revents = POLLIN | POLLOUT;
 
-    for (backoff = 1; ; backoff = MIN(backoff * 2, 60)) {
-        int retval = vconn_open(this->name, &this->vconn);
+    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));
+            sleep(this->backoff_deadline - now);
+        }
+
+        retval = vconn_open(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), reconnecting",
-                  this->name, strerror(errno));
-        sleep(backoff);
+        VLOG_WARN("%s: connection failed (%s)", this->name, strerror(errno));
+        this->backoff_deadline = time(0) + this->backoff;
     }
 }
 
@@ -199,6 +222,11 @@ parse_options(int argc, char *argv[])
         {"verbose",     optional_argument, 0, 'v'},
         {"help",        no_argument, 0, 'h'},
         {"version",     no_argument, 0, 'V'},
+#ifdef HAVE_OPENSSL
+        {"private-key", required_argument, 0, 'p'},
+        {"certificate", required_argument, 0, 'c'},
+        {"ca-cert",     required_argument, 0, 'C'},
+#endif
         {0, 0, 0, 0},
     };
     char *short_options = long_options_to_short_options(long_options);
@@ -228,6 +256,20 @@ parse_options(int argc, char *argv[])
             vlog_set_verbosity(optarg);
             break;
 
+#ifdef HAVE_OPENSSL
+        case 'p':
+            vconn_ssl_set_private_key_file(optarg);
+            break;
+
+        case 'c':
+            vconn_ssl_set_certificate_file(optarg);
+            break;
+
+        case 'C':
+            vconn_ssl_set_ca_cert_file(optarg);
+            break;
+#endif
+
         case '?':
             exit(EXIT_FAILURE);
 
@@ -242,15 +284,27 @@ static void
 usage(void)
 {
     printf("%s: Secure Channel\n"
-           "usage: %s [OPTIONS] nl:DP_ID tcp:HOST:[PORT]\n"
-           "\nConnects to local datapath DP_ID via Netlink and \n"
-           "controller on HOST via TCP to PORT (default: %d).\n"
-           "\nNetworking options:\n"
+           "usage: %s [OPTIONS] LOCAL REMOTE\n"
+           "\nRelays OpenFlow message between LOCAL and REMOTE datapaths.\n"
+           "LOCAL and REMOTE must each be one of the following:\n"
+           "  tcp:HOST[:PORT]         PORT (default: %d) on remote TCP HOST\n",
+           program_name, program_name, OFP_TCP_PORT);
+#ifdef HAVE_NETLINK
+    printf("  nl:DP_IDX               local datapath DP_IDX\n");
+#endif
+#ifdef HAVE_OPENSSL
+    printf("  ssl:HOST[:PORT]         SSL PORT (default: %d) on remote HOST\n"
+           "\nPKI configuration (required to use SSL):\n"
+           "  -p, --private-key=FILE  file with private key\n"
+           "  -c, --certificate=FILE  file with certificate for private key\n"
+           "  -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"
            "  -v, --verbose           set maximum verbosity level\n"
            "  -h, --help              display this help message\n"
-           "  -V, --version           display version information\n",
-           program_name, program_name, OFP_TCP_PORT);
+           "  -V, --version           display version information\n");
     exit(EXIT_SUCCESS);
 }