Allow secchan to listen for management connections also.
authorBen Pfaff <blp@nicira.com>
Fri, 4 Apr 2008 23:20:28 +0000 (16:20 -0700)
committerBen Pfaff <blp@nicira.com>
Fri, 4 Apr 2008 23:20:55 +0000 (16:20 -0700)
This is needed in the userspace switch code also.  That
change is implemented in later change "Send replies to
OpenFlow requests only to the sender".  Really that part
of the change should be moved into this one, but intervening
changes are intertwined enough with the same code to
make that difficult.

lib/vconn-netlink.c
secchan/Makefile.am
secchan/secchan.c

index 05c7ab07c328fed1c0045b6e0811c47487c1945a..ca1f93d5ae07a7dc176c5646b8acbbb378c4f1ff 100644 (file)
@@ -72,16 +72,18 @@ netlink_open(const char *name, char *suffix, struct vconn **vconnp)
 {
     struct netlink_vconn *netlink;
     int dp_idx;
+    int subscribe;
     int retval;
 
-    if (sscanf(suffix, "%d", &dp_idx) != 1) {
-        fatal(0, "%s: bad peer name format", name);
+    subscribe = 1;
+    if (sscanf(suffix, "%d:%d", &dp_idx, &subscribe) < 1) {
+        fatal(0, "%s: syntax error", name);
     }
 
     netlink = xmalloc(sizeof *netlink);
     netlink->vconn.class = &netlink_vconn_class;
     netlink->vconn.connect_status = 0;
-    retval = dpif_open(dp_idx, true, &netlink->dp);
+    retval = dpif_open(dp_idx, subscribe, &netlink->dp);
     if (retval) {
         free(netlink);
         *vconnp = NULL;
index 13ddb0446cb573967af1b786ecb4474d1a3ebc9c..882c98e7ecb43273e2cdfef9a51b5861bfdcd615 100644 (file)
@@ -1,6 +1,10 @@
 include ../Make.vars
 
+if HAVE_NETLINK
 bin_PROGRAMS = secchan
+else
+bin_PROGRAMS = 
+endif
 
 secchan_SOURCES = secchan.c
 secchan_LDADD = ../lib/libopenflow.la -ldl
index e24869363937bbaab4c2787ea4486a0e7e1140fe..72cbd257386b11d0113789b5103813d107e03ab9 100644 (file)
 #include "command-line.h"
 #include "compiler.h"
 #include "fault.h"
+#include "list.h"
 #include "util.h"
 #include "rconn.h"
 #include "vconn-ssl.h"
 #include "vlog-socket.h"
 #include "openflow.h"
 #include "poll-loop.h"
+#include "vconn.h"
 
 #include "vlog.h"
 #define THIS_MODULE VLM_secchan
 static void parse_options(int argc, char *argv[]);
 static void usage(void) NO_RETURN;
 
-static bool reliable = true;
+static struct vconn *listen_vconn = NULL;
+
+struct half {
+    struct rconn *rconn;
+    struct buffer *rxbuf;
+};
+
+struct relay {
+    struct list node;
+    struct half halves[2];
+};
+
+static struct list relays = LIST_INITIALIZER(&relays);
+
+static void new_management_connection(const char *nl_name, struct vconn *new_remote);
+static void relay_create(struct rconn *, struct rconn *);
+static void relay_run(struct relay *);
+static void relay_wait(struct relay *);
+static void relay_destroy(struct relay *);
 
 int
 main(int argc, char *argv[])
 {
-    struct half {
-        struct rconn *rconn;
-        struct buffer *rxbuf;
-    };
-
-    struct half halves[2];
+    const char *nl_name;
     int retval;
-    int i;
 
     set_program_name(argv[0]);
     register_fault_handlers();
@@ -76,7 +90,14 @@ main(int argc, char *argv[])
     parse_options(argc, argv);
 
     if (argc - optind != 2) {
-        fatal(0, "exactly two peer arguments required; use --help for usage");
+        fatal(0,
+              "need exactly two non-option arguments; use --help for usage");
+    }
+    nl_name = argv[optind];
+    if (strncmp(nl_name, "nl:", 3)
+        || strlen(nl_name) < 4
+        || nl_name[strspn(nl_name + 3, "0123456789") + 3]) {
+        fatal(0, "%s: argument is not of the form \"nl:DP_ID\"", nl_name);
     }
 
     retval = vlog_server_listen(NULL, NULL);
@@ -84,63 +105,165 @@ main(int argc, char *argv[])
         fatal(retval, "Could not listen for vlog connections");
     }
 
-    for (i = 0; i < 2; i++) {
-        halves[i].rconn = rconn_new(argv[optind + i], 1);
-        halves[i].rxbuf = NULL;
-    }
+    relay_create(rconn_new(argv[optind], 1), rconn_new(argv[optind + 1], 1));
     for (;;) {
-        /* Do some work.  Limit the number of iterations so that callbacks
-         * registered with the poll loop don't starve. */
-        int iteration;
+        struct relay *r, *n;
 
-        for (i = 0; i < 2; i++) {
-            rconn_run(halves[i].rconn);
+        /* Do work. */
+        LIST_FOR_EACH_SAFE (r, n, struct relay, node, &relays) {
+            relay_run(r);
         }
-
-        for (iteration = 0; iteration < 50; iteration++) {
-            bool progress = false;
-            for (i = 0; i < 2; i++) {
-                struct half *this = &halves[i];
-                struct half *peer = &halves[!i];
-
-                if (!this->rxbuf) {
-                    this->rxbuf = rconn_recv(this->rconn);
-                }
-
-                if (this->rxbuf) {
-                    retval = rconn_send(peer->rconn, this->rxbuf);
+        if (listen_vconn) {
+            struct vconn *new_remote;
+            for (;;) {
+                retval = vconn_accept(listen_vconn, &new_remote);
+                if (retval) {
                     if (retval != EAGAIN) {
-                        this->rxbuf = NULL;
-                        if (!retval) {
-                            progress = true;
-                        }
+                        VLOG_WARN("accept failed (%s)", strerror(retval));
                     }
+                    break;
                 }
-            }
-            if (!progress) {
-                break;
+
+                new_management_connection(nl_name, new_remote);
             }
         }
 
         /* Wait for something to happen. */
+        LIST_FOR_EACH (r, struct relay, node, &relays) {
+            relay_wait(r);
+        }
+        if (listen_vconn) {
+            vconn_accept_wait(listen_vconn);
+        }
+        poll_block();
+    }
+
+    return 0;
+}
+
+static void
+new_management_connection(const char *nl_name, struct vconn *new_remote)
+{
+    char *nl_name_without_subscription;
+    struct vconn *new_local;
+    struct rconn *r1, *r2;
+    int retval;
+
+    /* nl:123 or nl:123:1 opens a netlink connection to local datapath 123.  We
+     * only accept the former syntax in main().
+     *
+     * nl:123:0 opens a netlink connection to local datapath 123 without
+     * obtaining a subscription for ofp_packet_in or ofp_flow_expired
+     * messages.*/
+    nl_name_without_subscription = xasprintf("%s:0", nl_name);
+    retval = vconn_open(nl_name_without_subscription, &new_local);
+    if (retval) {
+        VLOG_ERR("could not connect to %s (%s)",
+                 nl_name_without_subscription, strerror(retval));
+        vconn_close(new_remote);
+        return;
+    }
+    free(nl_name_without_subscription);
+
+    /* Add it to the relay list. */
+    r1 = rconn_new_from_vconn(nl_name_without_subscription, 1, new_local);
+    r2 = rconn_new_from_vconn("passive", 1, new_remote);
+    relay_create(r1, r2);
+}
+
+static void
+relay_create(struct rconn *a, struct rconn *b)
+{
+    struct relay *r;
+    int i;
+
+    r = xmalloc(sizeof *r);
+    for (i = 0; i < 2; i++) {
+        r->halves[i].rconn = i ? b : a;
+        r->halves[i].rxbuf = NULL;
+    }
+    list_push_back(&relays, &r->node);
+}
+
+static void
+relay_run(struct relay *r)
+{
+    int iteration;
+    int i;
+
+    for (i = 0; i < 2; i++) {
+        rconn_run(r->halves[i].rconn);
+    }
+
+    /* Limit the number of iterations to prevent other tasks from starving. */
+    for (iteration = 0; iteration < 50; iteration++) {
+        bool progress = false;
         for (i = 0; i < 2; i++) {
-            struct half *this = &halves[i];
+            struct half *this = &r->halves[i];
+            struct half *peer = &r->halves[!i];
 
-            rconn_run_wait(this->rconn);
             if (!this->rxbuf) {
-                rconn_recv_wait(this->rconn);
+                this->rxbuf = rconn_recv(this->rconn);
+            }
+
+            if (this->rxbuf) {
+                int retval = rconn_send(peer->rconn, this->rxbuf);
+                if (retval != EAGAIN) {
+                    this->rxbuf = NULL;
+                    if (!retval) {
+                        progress = true;
+                    }
+                }
             }
         }
-        poll_block();
+        if (!progress) {
+            break;
+        }
     }
 
-    return 0;
+    for (i = 0; i < 2; i++) {
+        struct half *this = &r->halves[i];
+        if (!rconn_is_alive(this->rconn)) {
+            relay_destroy(r);
+            return;
+        }
+    }
+}
+
+static void
+relay_wait(struct relay *r)
+{
+    int i;
+
+    for (i = 0; i < 2; i++) {
+        struct half *this = &r->halves[i];
+
+        rconn_run_wait(this->rconn);
+        if (!this->rxbuf) {
+            rconn_recv_wait(this->rconn);
+        }
+    }
+}
+
+static void
+relay_destroy(struct relay *r)
+{
+    int i;
+
+    list_remove(&r->node);
+    for (i = 0; i < 2; i++) {
+        struct half *this = &r->halves[i];
+        rconn_destroy(this->rconn);
+        buffer_delete(this->rxbuf);
+    }
+    free(r);
 }
 
 static void
 parse_options(int argc, char *argv[]) 
 {
     static struct option long_options[] = {
+        {"listen",      required_argument, 0, 'l'},
         {"verbose",     optional_argument, 0, 'v'},
         {"help",        no_argument, 0, 'h'},
         {"version",     no_argument, 0, 'V'},
@@ -154,15 +277,28 @@ parse_options(int argc, char *argv[])
     char *short_options = long_options_to_short_options(long_options);
     
     for (;;) {
-        int indexptr;
+        int retval;
         int c;
 
-        c = getopt_long(argc, argv, short_options, long_options, &indexptr);
+        c = getopt_long(argc, argv, short_options, long_options, NULL);
         if (c == -1) {
             break;
         }
 
         switch (c) {
+        case 'l':
+            if (listen_vconn) {
+                fatal(0, "-l or --listen may be only specified once");
+            }
+            retval = vconn_open(optarg, &listen_vconn);
+            if (retval && retval != EAGAIN) {
+                fatal(retval, "opening %s", optarg);
+            }
+            if (!vconn_is_passive(listen_vconn)) {
+                fatal(0, "%s is not a passive vconn", optarg);
+            }
+            break;
+
         case 'h':
             usage();
 
@@ -217,6 +353,14 @@ usage(void)
            "  -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"
+           "  -l, --listen=VCONN      allow management connections on VCONN:\n"
+           "                          ptcp:[PORT]   TCP PORT (default: %d)\n",
+           OFP_TCP_PORT);
+#ifdef HAVE_OPENSSL
+    printf("                          pssl:[PORT]   SSL PORT (default: %d)\n",
+           OFP_SSL_PORT);
 #endif
     printf("\nOther options:\n"
            "  -v, --verbose           set maximum verbosity level\n"