[ovs-dev] [RFC] ovsdb: implement read-only remote connection type

Lance Richardson lrichard at redhat.com
Thu Oct 13 19:08:46 UTC 2016


This change set adds a new optional "access control" specifier to
remote connection descriptors used by ovsdb.

Examples:
    --remote=ptcp:ro:0:192.168.0.10
    --remote=punix:ro:asocket.sock
    --remote=pssl:ro:0:192.168.0.10
    --remote=tcp:ro:192.168.0.99:4444
    --remote=unix:ro:asocket.sock
    --remote=ssl:ro:192.168.0.10:4444

To-do:
   - documentation

Notes/questions:
    - Other possibilities might be worth considering, e.g.
      a "--remote-ro" command-line option that would be 
      analogous to "--remote"). This approach was cooked
      up in the dark, might not be to everyone's taste, and
      could easily be scrapped in favor of another approach
      if needed.

Side-note about odd autotest behavior:

 Doing 'make check TESTSUITEFLAGS="1876-1881"' executes these test
 cases:
    1876: ovsdb-server/read-only ptcp connection          ok
    1877: ovsdb-server/read-only punix connection         ok
    1878: ovsdb-server/read-only pssl connection          ok
    1879: ovsdb-server/read-only tcp connection           ok
    1880: ovsdb-server/read-only unix connection          ok
    1881: ovsdb-server/read-only ssl connection           ok

 But doing 'make check TESTSUITEFLAGS="-k read-only"' only executes
 these:
    1876: ovsdb-server/read-only ptcp connection          ok
    1877: ovsdb-server/read-only punix connection         ok
    1879: ovsdb-server/read-only tcp connection           ok
    1880: ovsdb-server/read-only unix connection          ok

 Shouldn't they all match the "read-only" keyword??


Signed-off-by: Lance Richardson <lrichard at redhat.com>
---

 lib/stream-ssl.c                          |  11 +-
 lib/stream-tcp.c                          |  21 +--
 lib/stream.c                              |  98 +++++++++++++-
 lib/stream.h                              |   4 +-
 ovn/controller-vtep/ovn-controller-vtep.c |   2 +-
 ovn/controller/ovn-controller.c           |   2 +-
 ovn/northd/ovn-northd.c                   |   2 +-
 ovn/utilities/ovn-sbctl.c                 |   2 +-
 ovn/utilities/ovn-trace.c                 |   2 +-
 ovsdb/jsonrpc-server.c                    |   7 +-
 ovsdb/ovsdb-client.c                      |   2 +-
 ovsdb/ovsdb-server.c                      |   2 +-
 tests/ovsdb-server.at                     | 208 ++++++++++++++++++++++++++++++
 tests/test-jsonrpc.c                      |   2 +-
 utilities/ovs-vsctl.c                     |   2 +-
 vswitchd/ovs-vswitchd.c                   |   2 +-
 vtep/vtep-ctl.c                           |   2 +-
 17 files changed, 337 insertions(+), 34 deletions(-)

diff --git a/lib/stream-ssl.c b/lib/stream-ssl.c
index a5c32a1..2443005 100644
--- a/lib/stream-ssl.c
+++ b/lib/stream-ssl.c
@@ -778,13 +778,14 @@ pssl_pstream_cast(struct pstream *pstream)
 }
 
 static int
-pssl_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp,
+pssl_open(const char *name, char *suffix, struct pstream **pstreamp,
           uint8_t dscp)
 {
     char bound_name[SS_NTOP_BUFSIZE + 16];
     char addrbuf[SS_NTOP_BUFSIZE];
     struct sockaddr_storage ss;
     struct pssl_pstream *pssl;
+    const char *access = "";
     uint16_t port;
     int retval;
     int fd;
@@ -799,9 +800,13 @@ pssl_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp,
         return -fd;
     }
 
+    if (!strncmp(name, "pssl:ro:", 8)) {
+        access = "ro:";
+    }
+
     port = ss_get_port(&ss);
-    snprintf(bound_name, sizeof bound_name, "pssl:%"PRIu16":%s",
-             port, ss_format_address(&ss, addrbuf, sizeof addrbuf));
+    snprintf(bound_name, sizeof bound_name, "pssl:%s%"PRIu16":%s",
+             access, port, ss_format_address(&ss, addrbuf, sizeof addrbuf));
 
     pssl = xmalloc(sizeof *pssl);
     pstream_init(&pssl->pstream, &pssl_pstream_class, bound_name);
diff --git a/lib/stream-tcp.c b/lib/stream-tcp.c
index 1749fad..e0aaa68 100644
--- a/lib/stream-tcp.c
+++ b/lib/stream-tcp.c
@@ -84,13 +84,13 @@ static int
 new_pstream(char *suffix, const char *name, struct pstream **pstreamp,
             int dscp, char *unlink_path, bool kernel_print_port)
 {
-    char bound_name[SS_NTOP_BUFSIZE + 16];
+    char bound_name[SS_NTOP_BUFSIZE + 20];
     char addrbuf[SS_NTOP_BUFSIZE];
     struct sockaddr_storage ss;
+    const char *access = "";
     int error;
     uint16_t port;
     int fd;
-    char *conn_name = CONST_CAST(char *, name);
 
     fd = inet_open_passive(SOCK_STREAM, suffix, -1, &ss, dscp,
                            kernel_print_port);
@@ -98,14 +98,15 @@ new_pstream(char *suffix, const char *name, struct pstream **pstreamp,
         return -fd;
     }
 
-    port = ss_get_port(&ss);
-    if (!conn_name) {
-        snprintf(bound_name, sizeof bound_name, "ptcp:%"PRIu16":%s",
-                 port, ss_format_address(&ss, addrbuf, sizeof addrbuf));
-        conn_name = bound_name;
+    if (!strncmp(name, "ptcp:ro:", 8)) {
+        access = "ro:";
     }
 
-    error = new_fd_pstream(conn_name, fd, ptcp_accept, unlink_path, pstreamp);
+    port = ss_get_port(&ss);
+    snprintf(bound_name, sizeof bound_name, "ptcp:%s%"PRIu16":%s",
+             access, port, ss_format_address(&ss, addrbuf, sizeof addrbuf));
+
+    error = new_fd_pstream(bound_name, fd, ptcp_accept, unlink_path, pstreamp);
     if (!error) {
         pstream_set_bound_port(*pstreamp, htons(port));
     }
@@ -113,10 +114,10 @@ new_pstream(char *suffix, const char *name, struct pstream **pstreamp,
 }
 
 static int
-ptcp_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp,
+ptcp_open(const char *name, char *suffix, struct pstream **pstreamp,
           uint8_t dscp)
 {
-    return new_pstream(suffix, NULL, pstreamp, dscp, NULL, true);
+    return new_pstream(suffix, name, pstreamp, dscp, NULL, true);
 }
 
 static int
diff --git a/lib/stream.c b/lib/stream.c
index f6ea849..b57b75e 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -116,7 +116,7 @@ check_stream_classes(void)
  * connection methods supported by the stream. */
 void
 stream_usage(const char *name, bool active, bool passive,
-             bool bootstrap OVS_UNUSED)
+             bool bootstrap OVS_UNUSED, bool access)
 {
     /* Really this should be implemented via callbacks into the stream
      * providers, but that seems too heavy-weight to bother with at the
@@ -135,6 +135,17 @@ stream_usage(const char *name, bool active, bool passive,
                "Unix domain socket named FILE\n");
     }
 
+    if (active && access) {
+        printf("  tcp:ro:IP:PORT          "
+               "PORT at remote IP (read-only access)\n");
+#ifdef HAVE_OPENSSL
+        printf("  ssl:ro:IP:PORT          "
+               "SSL PORT at remote IP (read-only access)\n");
+#endif
+        printf("  unix:FILE               "
+               "Unix domain socket named FILE (read-only access)\n");
+    }
+
     if (passive) {
         printf("Passive %s connection methods:\n", name);
         printf("  ptcp:PORT[:IP]          "
@@ -147,6 +158,17 @@ stream_usage(const char *name, bool active, bool passive,
                "listen on Unix domain socket FILE\n");
     }
 
+    if (passive && access) {
+        printf("  ptcp:ro:PORT[:IP]       "
+               "listen to TCP PORT on IP (read-only access)\n");
+#ifdef HAVE_OPENSSL
+        printf("  pssl:ro:PORT[:IP]       "
+               "listen for SSL on PORT on IP (read-only access)\n");
+#endif
+        printf("  punix:ro:FILE           "
+               "listen on Unix domain socket FILE (read-only access)\n");
+    }
+
 #ifdef HAVE_OPENSSL
     printf("PKI configuration (required to use SSL):\n"
            "  -p, --private-key=FILE  file with private key\n"
@@ -209,6 +231,7 @@ stream_open(const char *name, struct stream **streamp, uint8_t dscp)
     const struct stream_class *class;
     struct stream *stream;
     char *suffix_copy;
+    const char *next;
     int error;
 
     COVERAGE_INC(stream_open);
@@ -219,8 +242,16 @@ stream_open(const char *name, struct stream **streamp, uint8_t dscp)
         goto error;
     }
 
+    /* Check for read-only/read-write access specifier */
+    next = strchr(name, ':') + 1;
+    if (!strncmp(next, "ro:", 3)) {
+        next += 3;
+    } else if (!strncmp(next, "rw:", 3)) {
+        next += 3;
+    }
+
     /* Call class's "open" function. */
-    suffix_copy = xstrdup(strchr(name, ':') + 1);
+    suffix_copy = xstrdup(next);
     error = class->open(name, suffix_copy, &stream, dscp);
     free(suffix_copy);
     if (error) {
@@ -486,6 +517,30 @@ stream_or_pstream_needs_probes(const char *name)
     }
 }
 
+/* Returns 1 if the stream or pstream specified by 'name' includes a read-
+ * only access specification. */
+int
+stream_or_pstream_is_read_only(const char *name)
+{
+    const struct pstream_class *pclass;
+    const struct stream_class *class;
+    const char *next;
+
+    if (!stream_lookup_class(name, &class)) {
+        next = strchr(name, ':') + 1;
+        if (!strncmp(next, "ro:", 3)) {
+            return true;
+        }
+    } else if (!pstream_lookup_class(name, &pclass)) {
+        next = strchr(name, ':') + 1;
+        if (!strncmp(next, "ro:", 3)) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 /* Attempts to start listening for remote stream connections.  'name' is a
  * connection name in the form "TYPE:ARGS", where TYPE is an passive stream
  * class's name and ARGS are stream class-specific.
@@ -499,6 +554,7 @@ pstream_open(const char *name, struct pstream **pstreamp, uint8_t dscp)
     const struct pstream_class *class;
     struct pstream *pstream;
     char *suffix_copy;
+    const char *next;
     int error;
 
     COVERAGE_INC(pstream_open);
@@ -509,8 +565,16 @@ pstream_open(const char *name, struct pstream **pstreamp, uint8_t dscp)
         goto error;
     }
 
+    /* Check for read-only/read-write access specifier */
+    next = strchr(name, ':') + 1;
+    if (!strncmp(next, "ro:", 3)) {
+        next += 3;
+    } else if (!strncmp(next, "rw:", 3)) {
+        next += 3;
+    }
+
     /* Call class's "open" function. */
-    suffix_copy = xstrdup(strchr(name, ':') + 1);
+    suffix_copy = xstrdup(next);
     error = class->listen(name, suffix_copy, &pstream, dscp);
     free(suffix_copy);
     if (error) {
@@ -674,7 +738,19 @@ stream_open_with_default_port(const char *name_,
     char *name;
     int error;
 
-    if ((!strncmp(name_, "tcp:", 4) || !strncmp(name_, "ssl:", 4))
+    if ((!strncmp(name_, "tcp:ro:", 7) || !strncmp(name_, "ssl:ro:", 7))
+        && count_fields(name_) < 4) {
+        if (default_port == OFP_PORT) {
+            VLOG_WARN_ONCE("The default OpenFlow port number has changed "
+                           "from %d to %d",
+                           OFP_OLD_PORT, OFP_PORT);
+        } else if (default_port == OVSDB_PORT) {
+            VLOG_WARN_ONCE("The default OVSDB port number has changed "
+                           "from %d to %d",
+                           OVSDB_OLD_PORT, OVSDB_PORT);
+        }
+        name = xasprintf("%s:%d", name_, default_port);
+    } else if ((!strncmp(name_, "tcp:", 4) || !strncmp(name_, "ssl:", 4))
         && count_fields(name_) < 3) {
         if (default_port == OFP_PORT) {
             VLOG_WARN_ONCE("The default OpenFlow port number has changed "
@@ -706,7 +782,10 @@ pstream_open_with_default_port(const char *name_,
     char *name;
     int error;
 
-    if ((!strncmp(name_, "ptcp:", 5) || !strncmp(name_, "pssl:", 5))
+    if ((!strncmp(name_, "ptcp:ro:", 8) || !strncmp(name_, "pssl:ro:", 8))
+        && count_fields(name_) < 3) {
+        name = xasprintf("%s%d", name_, default_port);
+    } else if ((!strncmp(name_, "ptcp:", 5) || !strncmp(name_, "pssl:", 5))
         && count_fields(name_) < 2) {
         name = xasprintf("%s%d", name_, default_port);
     } else {
@@ -731,8 +810,13 @@ stream_parse_target_with_default_port(const char *target,
                                       uint16_t default_port,
                                       struct sockaddr_storage *ss)
 {
-    return ((!strncmp(target, "tcp:", 4) || !strncmp(target, "ssl:", 4))
-            && inet_parse_active(target + 4, default_port, ss));
+    if (!strncmp(target, "tcp:ro:", 7) || !strncmp(target, "ssl:ro:", 7)) {
+            return inet_parse_active(target + 7, default_port, ss);
+    } else if (!strncmp(target, "tcp:", 4) || !strncmp(target, "ssl:", 4)) {
+            return inet_parse_active(target + 4, default_port, ss);
+    } else {
+        return false;
+    }
 }
 
 /* Attempts to guess the content type of a stream whose first few bytes were
diff --git a/lib/stream.h b/lib/stream.h
index f8e1891..bded34d 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -29,7 +29,8 @@ struct pstream;
 struct stream;
 struct vlog_module;
 
-void stream_usage(const char *name, bool active, bool passive, bool bootstrap);
+void stream_usage(const char *name, bool active, bool passive,
+                  bool bootstrap, bool access);
 
 /* Bidirectional byte streams. */
 int stream_verify_name(const char *name);
@@ -79,6 +80,7 @@ bool stream_parse_target_with_default_port(const char *target,
                                            uint16_t default_port,
                                            struct sockaddr_storage *ss);
 int stream_or_pstream_needs_probes(const char *name);
+int stream_or_pstream_is_read_only(const char *name);
 
 /* Error reporting. */
 
diff --git a/ovn/controller-vtep/ovn-controller-vtep.c b/ovn/controller-vtep/ovn-controller-vtep.c
index baee789..9c2ed75 100644
--- a/ovn/controller-vtep/ovn-controller-vtep.c
+++ b/ovn/controller-vtep/ovn-controller-vtep.c
@@ -256,7 +256,7 @@ Options:\n\
   -o, --options             list available options\n\
   -V, --version             display version information\n\
 ", program_name, program_name, default_db(), default_db());
-    stream_usage("database", true, false, false);
+    stream_usage("database", true, false, false, false);
     daemon_usage();
     vlog_usage();
     exit(EXIT_SUCCESS);
diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c
index 4ac1425..2c7d743 100644
--- a/ovn/controller/ovn-controller.c
+++ b/ovn/controller/ovn-controller.c
@@ -749,7 +749,7 @@ usage(void)
            "usage %s [OPTIONS] [OVS-DATABASE]\n"
            "where OVS-DATABASE is a socket on which the OVS OVSDB server is listening.\n",
                program_name, program_name);
-    stream_usage("OVS-DATABASE", true, false, false);
+    stream_usage("OVS-DATABASE", true, false, false, false);
     daemon_usage();
     vlog_usage();
     printf("\nOther options:\n"
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index 281dc62..b0da206 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -223,7 +223,7 @@ Options:\n\
 ", program_name, program_name, default_nb_db(), default_sb_db());
     daemon_usage();
     vlog_usage();
-    stream_usage("database", true, true, false);
+    stream_usage("database", true, true, false, false);
 }
 
 struct tnlid_node {
diff --git a/ovn/utilities/ovn-sbctl.c b/ovn/utilities/ovn-sbctl.c
index b894b8b..e064330 100644
--- a/ovn/utilities/ovn-sbctl.c
+++ b/ovn/utilities/ovn-sbctl.c
@@ -326,7 +326,7 @@ Options:\n\
 Other options:\n\
   -h, --help                  display this help message\n\
   -V, --version               display version information\n");
-    stream_usage("database", true, true, false);
+    stream_usage("database", true, true, false, false);
     exit(EXIT_SUCCESS);
 }
 
diff --git a/ovn/utilities/ovn-trace.c b/ovn/utilities/ovn-trace.c
index 7863f70..7b0eb2a 100644
--- a/ovn/utilities/ovn-trace.c
+++ b/ovn/utilities/ovn-trace.c
@@ -255,7 +255,7 @@ Other options:\n\
   --unixctl=SOCKET            set control socket name\n\
   -h, --help                  display this help message\n\
   -V, --version               display version information\n");
-    stream_usage("database", true, true, false);
+    stream_usage("database", true, true, false, false);
     exit(EXIT_SUCCESS);
 }
 
diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c
index 87fc240..fe99ffd 100644
--- a/ovsdb/jsonrpc-server.c
+++ b/ovsdb/jsonrpc-server.c
@@ -272,7 +272,8 @@ ovsdb_jsonrpc_server_add_remote(struct ovsdb_jsonrpc_server *svr,
 
     if (!listener) {
         ovsdb_jsonrpc_session_create(remote, jsonrpc_session_open(name, true),
-                                      svr->read_only);
+                                      svr->read_only ||
+                                      stream_or_pstream_is_read_only(name));
     }
     return remote;
 }
@@ -366,7 +367,9 @@ ovsdb_jsonrpc_server_run(struct ovsdb_jsonrpc_server *svr)
                 struct jsonrpc_session *js;
                 js = jsonrpc_session_open_unreliably(jsonrpc_open(stream),
                                                      remote->dscp);
-                ovsdb_jsonrpc_session_create(remote, js, svr->read_only);
+                ovsdb_jsonrpc_session_create(remote, js, svr->read_only ||
+                                             stream_or_pstream_is_read_only(
+                                             pstream_get_name(remote->listener)));
             } else if (error != EAGAIN) {
                 VLOG_WARN_RL(&rl, "%s: accept failed: %s",
                              pstream_get_name(remote->listener),
diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c
index 5f569e8..3bc4898 100644
--- a/ovsdb/ovsdb-client.c
+++ b/ovsdb/ovsdb-client.c
@@ -278,7 +278,7 @@ usage(void)
            "\nThe default SERVER is unix:%s/db.sock.\n"
            "The default DATABASE is Open_vSwitch.\n",
            program_name, program_name, ovs_rundir());
-    stream_usage("SERVER", true, true, true);
+    stream_usage("SERVER", true, true, true, false);
     printf("\nOutput formatting options:\n"
            "  -f, --format=FORMAT         set output formatting to FORMAT\n"
            "                              (\"table\", \"html\", \"csv\", "
diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c
index 0e3f9ac..ab284b8 100644
--- a/ovsdb/ovsdb-server.c
+++ b/ovsdb/ovsdb-server.c
@@ -1623,7 +1623,7 @@ usage(void)
            program_name, program_name, ovs_dbdir());
     printf("\nJSON-RPC options (may be specified any number of times):\n"
            "  --remote=REMOTE         connect or listen to REMOTE\n");
-    stream_usage("JSON-RPC", true, true, true);
+    stream_usage("JSON-RPC", true, true, true, true);
     daemon_usage();
     vlog_usage();
     replication_usage();
diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at
index 89a5bf9..a4ac687 100644
--- a/tests/ovsdb-server.at
+++ b/tests/ovsdb-server.at
@@ -1367,3 +1367,211 @@ AT_CHECK([diff dump1 dump2])
 dnl OVSDB_SERVER_SHUTDOWN
 dnl OVSDB_SERVER_SHUTDOWN2
 AT_CLEANUP
+
+AT_SETUP([ovsdb-server/read-only ptcp connection])
+AT_KEYWORDS([ovsdb server read-only])
+ordinal_schema > schema
+AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-server --log-file --detach --no-chdir --pidfile="`pwd`"/pid --unixctl="`pwd`"/unixctl --remote=ptcp:ro:0:127.0.0.1 db], [0], [ignore], [ignore])
+PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT])
+AT_CHECK([ovsdb-client get-schema-version tcp:127.0.0.1:$TCP_PORT ordinals], [0], [5.1.3
+])
+
+AT_CHECK([ovsdb-client transact tcp:127.0.0.1:$TCP_PORT \
+        ['["ordinals",
+         {"op": "insert",
+          "table": "ordinals",
+          "row": {"name": "two", "number": '2'}}
+         ]']], [0], [stdout], [ignore])
+cat stdout >> output
+AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [[[{"details":"insert operation not allowed when database server is in read only mode","error":"not allowed"}]]
+], [ignore])
+OVSDB_SERVER_SHUTDOWN
+AT_CLEANUP
+
+AT_SETUP([ovsdb-server/read-only punix connection])
+AT_KEYWORDS([ovsdb server read-only])
+ordinal_schema > schema
+AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-server --log-file --detach --no-chdir --pidfile="`pwd`"/pid --unixctl="`pwd`"/unixctl --remote=punix:ro:test-socket db], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-client get-schema-version unix:test-socket ordinals], [0], [5.1.3
+])
+
+AT_CHECK([ovsdb-client transact unix:test-socket \
+        ['["ordinals",
+         {"op": "insert",
+          "table": "ordinals",
+          "row": {"name": "two", "number": '2'}}
+         ]']], [0], [stdout], [ignore])
+cat stdout >> output
+AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [[[{"details":"insert operation not allowed when database server is in read only mode","error":"not allowed"}]]
+], [ignore])
+OVSDB_SERVER_SHUTDOWN
+AT_CLEANUP
+
+AT_SETUP([ovsdb-server/read-only pssl connection])
+AT_SKIP_IF([test "$HAVE_OPENSSL" = no])
+PKIDIR="$(cd $abs_top_builddir/tests && pwd)"
+AT_SKIP_IF([expr "$PKIDIR" : ".*[ 	'\"
+\\]"])
+AT_DATA([schema],
+  [[{"name": "mydb",
+     "tables": {
+       "SSL": {
+         "columns": {
+           "private_key": {"type": "string"},
+           "certificate": {"type": "string"},
+           "ca_cert": {"type": "string"}}},
+       "ordinals": {
+         "columns": {
+           "number": {"type": "integer"},
+           "name": {"type": "string"}},
+         "indexes": [["number"]]}
+    },
+     "version": "5.1.3",
+     "cksum": "12345678 9"}
+]])
+AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
+AT_CHECK(
+  [[ovsdb-tool transact db \
+     '["mydb",
+       {"op": "insert",
+        "table": "SSL",
+        "row": {"private_key": "'"$PKIDIR/testpki-privkey2.pem"'",
+                "certificate": "'"$PKIDIR/testpki-cert2.pem"'",
+                "ca_cert": "'"$PKIDIR/testpki-cacert.pem"'"}}]']],
+  [0], [ignore], [ignore])
+AT_CHECK(
+  [ovsdb-server --log-file --detach --no-chdir --pidfile="`pwd`"/pid \
+        --private-key=db:mydb,SSL,private_key \
+        --certificate=db:mydb,SSL,certificate \
+        --ca-cert=db:mydb,SSL,ca_cert \
+        --remote=pssl:ro:0:127.0.0.1 --unixctl="`pwd`"/unixctl db],
+  [0], [ignore], [ignore])
+PARSE_LISTENING_PORT([ovsdb-server.log], [SSL_PORT])
+AT_CHECK([ovsdb-client \
+        --private-key=$PKIDIR/testpki-privkey.pem \
+        --certificate=$PKIDIR/testpki-cert.pem \
+        --ca-cert=$PKIDIR/testpki-cacert.pem \
+        get-schema-version ssl:127.0.0.1:$SSL_PORT mydb], \
+        [0], [5.1.3
+])
+AT_CHECK([ovsdb-client \
+        --private-key=$PKIDIR/testpki-privkey.pem \
+        --certificate=$PKIDIR/testpki-cert.pem \
+        --ca-cert=$PKIDIR/testpki-cacert.pem \
+        transact ssl:127.0.0.1:$SSL_PORT \
+        ['["mydb",
+         {"op": "insert",
+          "table": "ordinals",
+          "row": {"name": "two", "number": '2'}}
+         ]']], [0], [stdout], [ignore])
+cat stdout >> output
+AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [[[{"details":"insert operation not allowed when database server is in read only mode","error":"not allowed"}]]
+], [ignore])
+OVSDB_SERVER_SHUTDOWN
+AT_CLEANUP
+
+AT_SETUP([ovsdb-server/read-only tcp connection])
+AT_KEYWORDS([ovsdb server read-only])
+ordinal_schema > schema
+AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-server --log-file --detach --no-chdir --pidfile="`pwd`"/pid --unixctl="`pwd`"/unixctl --remote=tcp:ro:127.0.0.1:5551 db], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-client -vwarn get-schema-version ptcp:5551:127.0.0.1 ordinals], [0], [5.1.3
+])
+
+AT_CHECK([ovsdb-client transact ptcp:5551:127.0.0.1 \
+        ['["ordinals",
+         {"op": "insert",
+          "table": "ordinals",
+          "row": {"name": "two", "number": '2'}}
+         ]']], [0], [stdout], [ignore])
+cat stdout >> output
+AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [[[{"details":"insert operation not allowed when database server is in read only mode","error":"not allowed"}]]
+], [ignore])
+OVSDB_SERVER_SHUTDOWN
+AT_CLEANUP
+
+AT_SETUP([ovsdb-server/read-only unix connection])
+AT_KEYWORDS([ovsdb server read-only])
+ordinal_schema > schema
+AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-server --log-file --detach --no-chdir --pidfile="`pwd`"/pid --unixctl="`pwd`"/unixctl --remote=unix:ro:test-socket db], [0], [ignore], [ignore])
+ovsdb-client -v get-schema-version punix:test-socket ordinals
+AT_CHECK([ovsdb-client -vwarn get-schema-version punix:test-socket ordinals], [0], [5.1.3
+])
+
+AT_CHECK([ovsdb-client transact punix:test-socket \
+        ['["ordinals",
+         {"op": "insert",
+          "table": "ordinals",
+          "row": {"name": "two", "number": '2'}}
+         ]']], [0], [stdout], [ignore])
+cat stdout >> output
+AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [[[{"details":"insert operation not allowed when database server is in read only mode","error":"not allowed"}]]
+], [ignore])
+OVSDB_SERVER_SHUTDOWN
+AT_CLEANUP
+
+AT_SETUP([ovsdb-server/read-only ssl connection])
+AT_SKIP_IF([test "$HAVE_OPENSSL" = no])
+PKIDIR="$(cd $abs_top_builddir/tests && pwd)"
+AT_SKIP_IF([expr "$PKIDIR" : ".*[ 	'\"
+\\]"])
+AT_DATA([schema],
+  [[{"name": "mydb",
+     "tables": {
+       "SSL": {
+         "columns": {
+           "private_key": {"type": "string"},
+           "certificate": {"type": "string"},
+           "ca_cert": {"type": "string"}}},
+       "ordinals": {
+         "columns": {
+           "number": {"type": "integer"},
+           "name": {"type": "string"}},
+         "indexes": [["number"]]}
+    },
+     "version": "5.1.3",
+     "cksum": "12345678 9"}
+]])
+AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
+AT_CHECK(
+  [[ovsdb-tool transact db \
+     '["mydb",
+       {"op": "insert",
+        "table": "SSL",
+        "row": {"private_key": "'"$PKIDIR/testpki-privkey2.pem"'",
+                "certificate": "'"$PKIDIR/testpki-cert2.pem"'",
+                "ca_cert": "'"$PKIDIR/testpki-cacert.pem"'"}}]']],
+  [0], [ignore], [ignore])
+AT_CHECK(
+  [ovsdb-server --log-file --detach --no-chdir --pidfile="`pwd`"/pid \
+        --private-key=db:mydb,SSL,private_key \
+        --certificate=db:mydb,SSL,certificate \
+        --ca-cert=db:mydb,SSL,ca_cert \
+        --remote=ssl:ro:127.0.0.1:5552 --unixctl="`pwd`"/unixctl db],
+  [0], [ignore], [ignore])
+AT_CHECK([ovsdb-client -vwarn \
+        --private-key=$PKIDIR/testpki-privkey.pem \
+        --certificate=$PKIDIR/testpki-cert.pem \
+        --ca-cert=$PKIDIR/testpki-cacert.pem \
+        get-schema-version pssl:5552:127.0.0.1 mydb], \
+        [0], [5.1.3
+])
+AT_CHECK([ovsdb-client \
+        --private-key=$PKIDIR/testpki-privkey.pem \
+        --certificate=$PKIDIR/testpki-cert.pem \
+        --ca-cert=$PKIDIR/testpki-cacert.pem \
+        transact pssl:5552:127.0.0.1 \
+        ['["mydb",
+         {"op": "insert",
+          "table": "ordinals",
+          "row": {"name": "two", "number": '2'}}
+         ]']], [0], [stdout], [ignore])
+cat stdout >> output
+AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [[[{"details":"insert operation not allowed when database server is in read only mode","error":"not allowed"}]]
+], [ignore])
+OVSDB_SERVER_SHUTDOWN
+AT_CLEANUP
+
diff --git a/tests/test-jsonrpc.c b/tests/test-jsonrpc.c
index 684601a..7ee0681 100644
--- a/tests/test-jsonrpc.c
+++ b/tests/test-jsonrpc.c
@@ -108,7 +108,7 @@ usage(void)
            "  request REMOTE METHOD PARAMS   send request, print reply\n"
            "  notify REMOTE METHOD PARAMS  send notification and exit\n",
            program_name, program_name);
-    stream_usage("JSON-RPC", true, true, true);
+    stream_usage("JSON-RPC", true, true, true, false);
     daemon_usage();
     vlog_usage();
     printf("\nOther options:\n"
diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c
index e710095..c61f7df 100644
--- a/utilities/ovs-vsctl.c
+++ b/utilities/ovs-vsctl.c
@@ -424,7 +424,7 @@ Options:\n\
     vlog_usage();
     printf("\
   --no-syslog             equivalent to --verbose=vsctl:syslog:warn\n");
-    stream_usage("database", true, true, false);
+    stream_usage("database", true, true, false, false);
     printf("\n\
 Other options:\n\
   -h, --help                  display this help message\n\
diff --git a/vswitchd/ovs-vswitchd.c b/vswitchd/ovs-vswitchd.c
index 72448bb..ebc8d12 100644
--- a/vswitchd/ovs-vswitchd.c
+++ b/vswitchd/ovs-vswitchd.c
@@ -250,7 +250,7 @@ usage(void)
            "where DATABASE is a socket on which ovsdb-server is listening\n"
            "      (default: \"unix:%s/db.sock\").\n",
            program_name, program_name, ovs_rundir());
-    stream_usage("DATABASE", true, false, true);
+    stream_usage("DATABASE", true, false, true, false);
     daemon_usage();
     vlog_usage();
     printf("\nDPDK options:\n"
diff --git a/vtep/vtep-ctl.c b/vtep/vtep-ctl.c
index 245ba0d..01586ac 100644
--- a/vtep/vtep-ctl.c
+++ b/vtep/vtep-ctl.c
@@ -370,7 +370,7 @@ Options:\n\
     vlog_usage();
     printf("\
   --no-syslog                 equivalent to --verbose=vtep_ctl:syslog:warn\n");
-    stream_usage("database", true, true, false);
+    stream_usage("database", true, true, false, false);
     printf("\n\
 Other options:\n\
   -h, --help                  display this help message\n\
-- 
2.5.5




More information about the dev mailing list