[ovs-dev] [PATCH 2/2] Diagnose attempts to connect the wrong protocol to a network port.

Ben Pfaff blp at nicira.com
Wed May 5 17:31:58 UTC 2010


Sometimes, when a user asks me to help debug a problem, it turns out that
an SSL connection was being made on a TCP port, or vice versa, or that an
OpenFlow connection was being made on a JSON-RPC port, or vice versa, and
so on.  This commit adds log messages that diagnose this kind of problem,
e.g. "tcp:127.0.0.1:6633: received JSON-RPC data on OpenFlow channel".
---
 lib/jsonrpc.c      |    6 +++++
 lib/stream-ssl.c   |   14 ++++++++++++
 lib/stream.c       |   61 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/stream.h       |   13 +++++++++++
 lib/vconn-stream.c |    9 +++++++
 5 files changed, 103 insertions(+), 0 deletions(-)

diff --git a/lib/jsonrpc.c b/lib/jsonrpc.c
index 828bdac..bb4f6ba 100644
--- a/lib/jsonrpc.c
+++ b/lib/jsonrpc.c
@@ -267,6 +267,12 @@ jsonrpc_recv(struct jsonrpc *rpc, struct jsonrpc_msg **msgp)
             if (json_parser_is_done(rpc->parser)) {
                 jsonrpc_received(rpc);
                 if (rpc->status) {
+                    const struct byteq *q = &rpc->input;
+                    if (q->head <= BYTEQ_SIZE) {
+                        stream_report_content(q->buffer, q->head,
+                                              STREAM_JSONRPC,
+                                              THIS_MODULE, rpc->name);
+                    }
                     return rpc->status;
                 }
             }
diff --git a/lib/stream-ssl.c b/lib/stream-ssl.c
index 27c9d4c..462ac42 100644
--- a/lib/stream-ssl.c
+++ b/lib/stream-ssl.c
@@ -124,6 +124,10 @@ struct ssl_stream
      * deadlock and livelock situations above.
      */
     int rx_want, tx_want;
+
+    /* A few bytes of header data in case SSL negotation fails. */
+    uint8_t head[2];
+    short int n_head;
 };
 
 /* SSL context created by ssl_init(). */
@@ -264,6 +268,7 @@ new_ssl_stream(const char *name, int fd, enum session_type type,
     sslv->ssl = ssl;
     sslv->txbuf = NULL;
     sslv->rx_want = sslv->tx_want = SSL_NOTHING;
+    sslv->n_head = 0;
     *streamp = &sslv->stream;
     return 0;
 
@@ -414,6 +419,13 @@ ssl_connect(struct stream *stream)
         /* Fall through. */
 
     case STATE_SSL_CONNECTING:
+        /* Capture the first few bytes of received data so that we can guess
+         * what kind of funny data we've been sent if SSL negotation fails. */
+        if (sslv->n_head <= 0) {
+            sslv->n_head = recv(sslv->fd, sslv->head, sizeof sslv->head,
+                                MSG_PEEK);
+        }
+
         retval = (sslv->type == CLIENT
                    ? SSL_connect(sslv->ssl) : SSL_accept(sslv->ssl));
         if (retval != 1) {
@@ -425,6 +437,8 @@ ssl_connect(struct stream *stream)
                 interpret_ssl_error((sslv->type == CLIENT ? "SSL_connect"
                                      : "SSL_accept"), retval, error, &unused);
                 shutdown(sslv->fd, SHUT_RDWR);
+                stream_report_content(sslv->head, sslv->n_head, STREAM_SSL,
+                                      THIS_MODULE, stream_get_name(stream));
                 return EPROTO;
             }
         } else if (bootstrap_ca_cert) {
diff --git a/lib/stream.c b/lib/stream.c
index 43b73af..667a23f 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -718,5 +718,66 @@ pstream_open_with_default_ports(const char *name_,
 
     return error;
 }
+
+/* Attempts to guess the content type of a stream whose first few bytes were
+ * the 'size' bytes of 'data'. */
+static enum stream_content_type
+stream_guess_content(const uint8_t *data, size_t size)
+{
+    if (size >= 2) {
+#define PAIR(A, B) (((A) << 8) | (B))
+        switch (PAIR(data[0], data[1])) {
+        case PAIR(0x16, 0x03):  /* Handshake, version 3. */
+            return STREAM_SSL;
+        case PAIR('{', '"'):
+            return STREAM_JSONRPC;
+        case PAIR(OFP_VERSION, OFPT_HELLO):
+            return STREAM_OPENFLOW;
+        }
+    }
+
+    return STREAM_UNKNOWN;
+}
+
+/* Returns a string represenation of 'type'. */
+static const char *
+stream_content_type_to_string(enum stream_content_type type)
+{
+    switch (type) {
+    case STREAM_UNKNOWN:
+    default:
+        return "unknown";
 
+    case STREAM_JSONRPC:
+        return "JSON-RPC";
 
+    case STREAM_OPENFLOW:
+        return "OpenFlow";
+
+    case STREAM_SSL:
+        return "SSL";
+    }
+}
+
+/* Attempts to guess the content type of a stream whose first few bytes were
+ * the 'size' bytes of 'data'.  If this is done successfully, and the guessed
+ * content type is other than 'expected_type', then log a message in vlog
+ * module 'module', naming 'stream_name' as the source, explaining what
+ * content was expected and what was actually received. */
+void
+stream_report_content(const void *data, size_t size,
+                      enum stream_content_type expected_type,
+                      enum vlog_module module, const char *stream_name)
+{
+    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
+    enum stream_content_type actual_type;
+
+    actual_type = stream_guess_content(data, size);
+    if (actual_type != expected_type && actual_type != STREAM_UNKNOWN) {
+        vlog_rate_limit(module, VLL_WARN, &rl,
+                        "%s: received %s data on %s channel",
+                        stream_name,
+                        stream_content_type_to_string(expected_type),
+                        stream_content_type_to_string(actual_type));
+    }
+}
diff --git a/lib/stream.h b/lib/stream.h
index d8b0814..256667e 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -20,6 +20,7 @@
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
+#include "vlog.h"
 
 struct pstream;
 struct stream;
@@ -72,5 +73,17 @@ int pstream_open_with_default_ports(const char *name,
                                     uint16_t default_ptcp_port,
                                     uint16_t default_pssl_port,
                                     struct pstream **);
+
+/* Error reporting. */
+
+enum stream_content_type {
+    STREAM_UNKNOWN,
+    STREAM_OPENFLOW,
+    STREAM_SSL,
+    STREAM_JSONRPC
+};
+
+void stream_report_content(const void *, size_t, enum stream_content_type,
+                           enum vlog_module, const char *stream_name);
 
 #endif /* stream.h */
diff --git a/lib/vconn-stream.c b/lib/vconn-stream.c
index a479a37..6667554 100644
--- a/lib/vconn-stream.c
+++ b/lib/vconn-stream.c
@@ -44,6 +44,7 @@ struct vconn_stream
     struct stream *stream;
     struct ofpbuf *rxbuf;
     struct ofpbuf *txbuf;
+    int n_packets;
 };
 
 static struct vconn_class stream_vconn_class;
@@ -63,6 +64,7 @@ vconn_stream_new(struct stream *stream, int connect_status)
     s->stream = stream;
     s->txbuf = NULL;
     s->rxbuf = NULL;
+    s->n_packets = 0;
     s->vconn.remote_ip = stream_get_remote_ip(stream);
     s->vconn.remote_port = stream_get_remote_port(stream);
     s->vconn.local_ip = stream_get_local_ip(stream);
@@ -102,6 +104,12 @@ static void
 vconn_stream_close(struct vconn *vconn)
 {
     struct vconn_stream *s = vconn_stream_cast(vconn);
+
+    if ((vconn->error == EPROTO || s->n_packets < 1) && s->rxbuf) {
+        stream_report_content(s->rxbuf->data, s->rxbuf->size, STREAM_OPENFLOW,
+                              THIS_MODULE, vconn_get_name(vconn));
+    }
+
     stream_close(s->stream);
     vconn_stream_clear_txbuf(s);
     ofpbuf_delete(s->rxbuf);
@@ -146,6 +154,7 @@ vconn_stream_recv(struct vconn *vconn, struct ofpbuf **bufferp)
                 return EPROTO;
             }
 
+            s->n_packets++;
             *bufferp = rx;
             s->rxbuf = NULL;
             return 0;
-- 
1.6.6.1





More information about the dev mailing list