Allow multiple -l or --listen options on secchan command line.
authorBen Pfaff <blp@nicira.com>
Wed, 27 Aug 2008 18:50:11 +0000 (11:50 -0700)
committerBen Pfaff <blp@nicira.com>
Wed, 27 Aug 2008 18:50:11 +0000 (11:50 -0700)
Bug #149.

secchan/secchan.8.in
secchan/secchan.c

index 12f390b0b50bcf026c632beeb26c0a89ae7867af..620c59f91686bb2cac1af045999a0e6a61ddfcc3 100644 (file)
@@ -281,8 +281,9 @@ time is 15 seconds.
 \fB-l\fR, \fB--listen=\fImethod\fR
 Configures the switch to additionally listen for incoming OpenFlow
 connections for switch management with \fBdpctl\fR.  The \fImethod\fR
-must be given as one of the following passive OpenFlow connection
-methods:
+must be given as one of the passive OpenFlow connection methods listed
+below.  This option may be specified multiple times to listen to
+multiple connection methods.
 
 .RS
 .TP
index 8906eb03117b6a365635e80fd0fd066f93706f4b..e21454029e1ea353e585e7deb50aff9fbda18f24 100644 (file)
@@ -77,6 +77,9 @@ enum fail_mode {
     FAIL_CLOSED                 /* Drop all packets. */
 };
 
+/* Maximum number of management connection listeners. */
+#define MAX_MGMT 8
+
 /* Settings that may be configured by the user. */
 struct settings {
     /* Overall mode of operation. */
@@ -87,7 +90,8 @@ struct settings {
     const char *nl_name;        /* Local datapath (must be "nl:" vconn). */
     char *of_name;              /* ofX network device name. */
     const char *controller_name; /* Controller (if not discovery mode). */
-    const char *listen_vconn_name; /* Listens for mgmt connections. */
+    const char *listener_names[MAX_MGMT]; /* Listen for mgmt connections. */
+    size_t n_listeners;          /* Number of mgmt connection listeners. */
 
     /* Failure behavior. */
     enum fail_mode fail_mode; /* Act as learning switch if no controller? */
@@ -191,11 +195,14 @@ main(int argc, char *argv[])
     struct hook hooks[8];
     size_t n_hooks = 0;
 
+    struct vconn *listeners[MAX_MGMT];
+    size_t n_listeners;
+
     struct rconn *local_rconn, *remote_rconn;
-    struct vconn *listen_vconn;
     struct relay *controller_relay;
     struct discovery *discovery;
     struct switch_status *switch_status;
+    int i;
     int retval;
 
     set_program_name(argv[0]);
@@ -206,16 +213,18 @@ main(int argc, char *argv[])
     signal(SIGPIPE, SIG_IGN);
 
     /* Start listening for management connections. */
-    if (s.listen_vconn_name) {
-        retval = vconn_open(s.listen_vconn_name, &listen_vconn);
+    n_listeners = 0;
+    for (i = 0; i < s.n_listeners; i++) {
+        const char *name = s.listener_names[i];
+        struct vconn *listener;
+        retval = vconn_open(name, &listener);
         if (retval && retval != EAGAIN) {
-            fatal(retval, "opening %s", s.listen_vconn_name);
+            fatal(retval, "opening %s", name);
         }
-        if (!vconn_is_passive(listen_vconn)) {
-            fatal(0, "%s is not a passive vconn", s.listen_vconn_name);
+        if (!vconn_is_passive(listener)) {
+            fatal(0, "%s is not a passive vconn", name);
         }
-    } else {
-        listen_vconn = NULL;
+        listeners[n_listeners++] = listener;
     }
 
     /* Initialize switch status hook. */
@@ -279,9 +288,9 @@ main(int argc, char *argv[])
         LIST_FOR_EACH_SAFE (r, n, struct relay, node, &relays) {
             relay_run(r, hooks, n_hooks);
         }
-        if (listen_vconn) {
+        for (i = 0; i < n_listeners; i++) {
             for (;;) {
-                struct relay *r = relay_accept(&s, listen_vconn);
+                struct relay *r = relay_accept(&s, listeners[i]);
                 if (!r) {
                     break;
                 }
@@ -311,8 +320,8 @@ main(int argc, char *argv[])
         LIST_FOR_EACH (r, struct relay, node, &relays) {
             relay_wait(r);
         }
-        if (listen_vconn) {
-            vconn_accept_wait(listen_vconn);
+        for (i = 0; i < n_listeners; i++) {
+            vconn_accept_wait(listeners[i]);
         }
         for (i = 0; i < n_hooks; i++) {
             if (hooks[i].wait_cb) {
@@ -1099,10 +1108,11 @@ rconn_status_cb(struct status_reply *sr, void *rconn_)
 static void
 config_status_cb(struct status_reply *sr, void *s_)
 {
-     const struct settings *s = s_;
+    const struct settings *s = s_;
+    size_t i;
 
-    if (s->listen_vconn_name) {
-        status_reply_put(sr, "management=%s", s->listen_vconn_name);
+    for (i = 0; i < s->n_listeners; i++) {
+        status_reply_put(sr, "management%zu=%s", i, s->listener_names[i]);
     }
     if (s->probe_interval) {
         status_reply_put(sr, "probe-interval=%d", s->probe_interval);
@@ -1371,7 +1381,7 @@ parse_options(int argc, char *argv[], struct settings *s)
     int retval;
 
     /* Set defaults that we can figure out before parsing options. */
-    s->listen_vconn_name = NULL;
+    s->n_listeners = 0;
     s->fail_mode = FAIL_OPEN;
     s->max_idle = 15;
     s->probe_interval = 15;
@@ -1462,10 +1472,11 @@ parse_options(int argc, char *argv[], struct settings *s)
             break;
 
         case 'l':
-            if (s->listen_vconn_name) {
-                fatal(0, "-l or --listen may be only specified once");
+            if (s->n_listeners >= MAX_MGMT) {
+                fatal(0, "-l or --listen may be specified at most %d times",
+                      MAX_MGMT);
             }
-            s->listen_vconn_name = optarg;
+            s->listener_names[s->n_listeners++] = optarg;
             break;
 
         case 'h':