[ovs-dev] [PATCH 2/2] ovn-controller: add local address for ovn-remote connection

Huang Lei 148012453 at qq.com
Fri Apr 22 08:14:25 UTC 2016


From: Huang Lei <lhuang8 at ebay.com>

Add a local address option for ovn-controller's TCP socket which
connect to southbound ovsdb-server.

In a test environment, an interface may have multiple IP addresses
in same subnet, if TCP client socket doesn't call bind() explicitly,
OS chooses an ip and port for it, and the IP is the primary IP of
the subnet on an interface. With this patch, a secondary IP of the
subnet can be used as local address of TCP connection.

Signed-off-by: Huang Lei <lhuang8 at ebay.com>
---
 lib/jsonrpc.c                   | 16 +++++++++++++---
 lib/jsonrpc.h                   |  6 ++++--
 lib/netdev-dummy.c              |  3 ++-
 lib/ovsdb-idl.c                 | 10 ++++++++++
 lib/ovsdb-idl.h                 |  1 +
 lib/reconnect.c                 | 20 ++++++++++++++++++++
 lib/reconnect.h                 |  2 ++
 lib/socket-util.c               | 23 ++++++++++++++++++++++-
 lib/socket-util.h               |  1 +
 lib/stream-provider.h           |  6 ++++--
 lib/stream-ssl.c                |  5 +++--
 lib/stream-tcp.c                | 11 ++++++-----
 lib/stream-unix.c               |  5 +++--
 lib/stream.c                    |  8 +++++---
 lib/stream.h                    |  4 +++-
 lib/syslog-direct.c             |  2 +-
 lib/unixctl.c                   |  2 +-
 lib/vconn-stream.c              |  2 +-
 lib/vlog.c                      |  2 +-
 ofproto/collectors.c            |  3 ++-
 ovn/controller/ovn-controller.c | 22 +++++++++++++++++++++-
 ovsdb/ovsdb-client.c            |  2 +-
 tests/test-jsonrpc.c            |  4 ++--
 tests/test-ovsdb.c              |  4 ++--
 24 files changed, 131 insertions(+), 33 deletions(-)

diff --git a/lib/jsonrpc.c b/lib/jsonrpc.c
index 1112b4a..c79f3ec 100644
--- a/lib/jsonrpc.c
+++ b/lib/jsonrpc.c
@@ -61,9 +61,10 @@ static void jsonrpc_error(struct jsonrpc *, int error);
 /* This is just the same as stream_open() except that it uses the default
  * JSONRPC port if none is specified. */
 int
-jsonrpc_stream_open(const char *name, struct stream **streamp, uint8_t dscp)
+jsonrpc_stream_open(const char *name, const char *local,
+                    struct stream **streamp, uint8_t dscp)
 {
-    return stream_open_with_default_port(name, OVSDB_PORT, streamp, dscp);
+    return stream_open_with_default_port(name, local, OVSDB_PORT, streamp, dscp);
 }

 /* This is just the same as pstream_open() except that it uses the default
@@ -862,11 +863,12 @@ static void
 jsonrpc_session_connect(struct jsonrpc_session *s)
 {
     const char *name = reconnect_get_name(s->reconnect);
+    const char *local = reconnect_get_local(s->reconnect);
     int error;

     jsonrpc_session_disconnect(s);
     if (!reconnect_is_passive(s->reconnect)) {
-        error = jsonrpc_stream_open(name, &s->stream, s->dscp);
+        error = jsonrpc_stream_open(name, local, &s->stream, s->dscp);
         if (!error) {
             reconnect_connecting(s->reconnect, time_msec());
         } else {
@@ -1164,3 +1166,11 @@ jsonrpc_session_set_dscp(struct jsonrpc_session *s, uint8_t dscp)
         jsonrpc_session_force_reconnect(s);
     }
 }
+
+/* Set the 'local' address used to connect to the remote host in active mode
+ * for TCP stream. */
+void
+jsonrpc_session_set_local(struct jsonrpc_session *s, const char *local)
+{
+    reconnect_set_local(s->reconnect, local);
+}
diff --git a/lib/jsonrpc.h b/lib/jsonrpc.h
index 5f46e3b..8db0690 100644
--- a/lib/jsonrpc.h
+++ b/lib/jsonrpc.h
@@ -39,7 +39,8 @@ struct stream;
 #define OVSDB_OLD_PORT 6632
 #define OVSDB_PORT 6640

-int jsonrpc_stream_open(const char *name, struct stream **, uint8_t dscp);
+int jsonrpc_stream_open(const char *name, const char *local,
+                        struct stream **, uint8_t dscp);
 int jsonrpc_pstream_open(const char *name, struct pstream **, uint8_t dscp);

 struct jsonrpc *jsonrpc_open(struct stream *);
@@ -130,5 +131,6 @@ void jsonrpc_session_set_probe_interval(struct jsonrpc_session *,
                                         int probe_interval);
 void jsonrpc_session_set_dscp(struct jsonrpc_session *,
                               uint8_t dscp);
-
+void jsonrpc_session_set_local(struct jsonrpc_session *,
+                              const char *local);
 #endif /* jsonrpc.h */
diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
index 5acb4e1..09f9d31 100644
--- a/lib/netdev-dummy.c
+++ b/lib/netdev-dummy.c
@@ -400,7 +400,7 @@ dummy_packet_conn_set_config(struct dummy_packet_conn *conn,
         conn->u.rconn.reconnect = reconnect;
         conn->type = ACTIVE;

-        error = stream_open(stream, &active_stream, DSCP_DEFAULT);
+        error = stream_open(stream, NULL, &active_stream, DSCP_DEFAULT);
         conn->u.rconn.rstream = dummy_packet_stream_create(active_stream);

         switch (error) {
@@ -476,6 +476,7 @@ OVS_REQUIRES(dev->mutex)
                 error = stream_connect(rconn->rstream->stream);
             } else {
                 error = stream_open(reconnect_get_name(rconn->reconnect),
+                                    NULL,
                                     &rconn->rstream->stream, DSCP_DEFAULT);
             }

diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
index a046b6b..6bec912 100644
--- a/lib/ovsdb-idl.c
+++ b/lib/ovsdb-idl.c
@@ -284,6 +284,16 @@ ovsdb_idl_set_remote(struct ovsdb_idl *idl, const char *remote,
     }
 }

+/* Set the 'local' address used to connect to the remote host in active mode
+ * for TCP stream. */
+void
+ovsdb_idl_set_local(struct ovsdb_idl *idl, const char *local)
+{
+    if (idl && local) {
+        jsonrpc_session_set_local(idl->session, local);
+    }
+}
+
 /* Destroys 'idl' and all of the data structures that it manages. */
 void
 ovsdb_idl_destroy(struct ovsdb_idl *idl)
diff --git a/lib/ovsdb-idl.h b/lib/ovsdb-idl.h
index bad2dc6..a29a12e 100644
--- a/lib/ovsdb-idl.h
+++ b/lib/ovsdb-idl.h
@@ -52,6 +52,7 @@ struct ovsdb_idl *ovsdb_idl_create(const char *remote,
                                    bool monitor_everything_by_default,
                                    bool retry);
 void ovsdb_idl_set_remote(struct ovsdb_idl *, const char *, bool);
+void ovsdb_idl_set_local(struct ovsdb_idl *, const char *);
 void ovsdb_idl_destroy(struct ovsdb_idl *);

 void ovsdb_idl_run(struct ovsdb_idl *);
diff --git a/lib/reconnect.c b/lib/reconnect.c
index bab821e..88ff010 100644
--- a/lib/reconnect.c
+++ b/lib/reconnect.c
@@ -47,6 +47,7 @@ is_connected_state(enum state state)
 struct reconnect {
     /* Configuration. */
     char *name;
+    char *local;
     int min_backoff;
     int max_backoff;
     int probe_interval;
@@ -119,6 +120,7 @@ reconnect_destroy(struct reconnect *fsm)
 {
     if (fsm) {
         free(fsm->name);
+        free(fsm->local);
         free(fsm);
     }
 }
@@ -146,6 +148,13 @@ reconnect_get_name(const struct reconnect *fsm)
     return fsm->name;
 }

+/* Returns 'fsm''s local address used in active mode. */
+const char *
+reconnect_get_local(const struct reconnect *fsm)
+{
+    return fsm->local;
+}
+
 /* Sets 'fsm''s name to 'name'.  If 'name' is null, then "void" is used
  * instead.
  *
@@ -157,6 +166,17 @@ reconnect_set_name(struct reconnect *fsm, const char *name)
     fsm->name = xstrdup(name ? name : "void");
 }

+/* Set 'fsm''s local address to 'local'. If 'local' is null, the local
+ * address will be selected by system.
+ *
+ * The local address set for 'fsm' is used in active mode for TCP stream. */
+void
+reconnect_set_local(struct reconnect *fsm, const char *local)
+{
+    free(fsm->local);
+    fsm->local = local ? xstrdup(local) : NULL;
+}
+
 /* Return the minimum number of milliseconds to back off between consecutive
  * connection attempts.  The default is RECONNECT_DEFAULT_MIN_BACKOFF. */
 int
diff --git a/lib/reconnect.h b/lib/reconnect.h
index 4446713..6265cee 100644
--- a/lib/reconnect.h
+++ b/lib/reconnect.h
@@ -39,6 +39,8 @@ void reconnect_set_quiet(struct reconnect *, bool quiet);

 const char *reconnect_get_name(const struct reconnect *);
 void reconnect_set_name(struct reconnect *, const char *name);
+const char *reconnect_get_local(const struct reconnect *);
+void reconnect_set_local(struct reconnect *, const char *local);

 /* Defaults, all in msecs. */
 #define RECONNECT_DEFAULT_MIN_BACKOFF 1000
diff --git a/lib/socket-util.c b/lib/socket-util.c
index 5a36f3b..1d4b540 100644
--- a/lib/socket-util.c
+++ b/lib/socket-util.c
@@ -442,13 +442,17 @@ inet_parse_active(const char *target_, uint16_t default_port,
  * into '*fdp'.  On failure, returns a positive errno value other than EAGAIN
  * and stores -1 into '*fdp'.
  *
- * If 'ss' is non-null, then on success stores the target address into '*ss'.
+ * If 'local' is non-null, then the socket will bind to the address
+ * specified by it.
+ *
+ * If 'ssp' is non-null, then on success stores the target address into '*ssp'.
  *
  * 'dscp' becomes the DSCP bits in the IP headers for the new connection.  It
  * should be in the range [0, 63] and will automatically be shifted to the
  * appropriately place in the IP tos field. */
 int
 inet_open_active(int style, const char *target, uint16_t default_port,
+                 const char *local,
                  struct sockaddr_storage *ssp, int *fdp, uint8_t dscp)
 {
     struct sockaddr_storage ss;
@@ -482,6 +486,23 @@ inet_open_active(int style, const char *target, uint16_t default_port,
         goto exit;
     }

+    if (local) {
+        struct sockaddr_storage ss_local;
+        if (!inet_parse_active(local, 0, &ss_local)) {
+            error = EAFNOSUPPORT;
+            VLOG_ERR("invalid local address %s", local);
+            goto exit;
+        }
+        error = bind(fd, (struct sockaddr *) &ss_local,
+                     ss_length(&ss_local)) == 0
+                     ? 0
+                     : sock_errno();
+        if (error) {
+            VLOG_ERR("%s: bind to %s failed", target, local);
+            goto exit;
+        }
+    }
+
     /* Connect. */
     error = connect(fd, (struct sockaddr *) &ss, ss_length(&ss)) == 0
                     ? 0
diff --git a/lib/socket-util.h b/lib/socket-util.h
index c3c1224..fcf2956 100644
--- a/lib/socket-util.h
+++ b/lib/socket-util.h
@@ -46,6 +46,7 @@ ovs_be32 guess_netmask(ovs_be32 ip);
 bool inet_parse_active(const char *target, uint16_t default_port,
                        struct sockaddr_storage *ssp);
 int inet_open_active(int style, const char *target, uint16_t default_port,
+                     const char *local,
                      struct sockaddr_storage *ssp, int *fdp, uint8_t dscp);

 bool inet_parse_passive(const char *target, int default_port,
diff --git a/lib/stream-provider.h b/lib/stream-provider.h
index 2226a80..6831f13 100644
--- a/lib/stream-provider.h
+++ b/lib/stream-provider.h
@@ -57,6 +57,8 @@ struct stream_class {
      * 'dscp' is the DSCP value that the new connection should use in the IP
      * packets it sends.
      *
+     * 'local' is the local address used in active mode for TCP stream.
+     *
      * Returns 0 if successful, otherwise a positive errno value.  If
      * successful, stores a pointer to the new connection in '*streamp'.
      *
@@ -64,8 +66,8 @@ struct stream_class {
      * If the connection cannot be completed immediately, it should return
      * EAGAIN (not EINPROGRESS, as returned by the connect system call) and
      * continue the connection in the background. */
-    int (*open)(const char *name, char *suffix, struct stream **streamp,
-                uint8_t dscp);
+    int (*open)(const char *name, char *suffix, const char *local,
+                struct stream **streamp, uint8_t dscp);

     /* Closes 'stream' and frees associated memory. */
     void (*close)(struct stream *stream);
diff --git a/lib/stream-ssl.c b/lib/stream-ssl.c
index bf80fc8..d963433 100644
--- a/lib/stream-ssl.c
+++ b/lib/stream-ssl.c
@@ -308,7 +308,8 @@ ssl_stream_cast(struct stream *stream)
 }

 static int
-ssl_open(const char *name, char *suffix, struct stream **streamp, uint8_t dscp)
+ssl_open(const char *name, char *suffix, const char *local,
+        struct stream **streamp, uint8_t dscp)
 {
     int error, fd;

@@ -317,7 +318,7 @@ ssl_open(const char *name, char *suffix, struct stream **streamp, uint8_t dscp)
         return error;
     }

-    error = inet_open_active(SOCK_STREAM, suffix, OFP_PORT, NULL, &fd,
+    error = inet_open_active(SOCK_STREAM, suffix, OFP_PORT, local, NULL, &fd,
                              dscp);
     if (fd >= 0) {
         int state = error ? STATE_TCP_CONNECTING : STATE_SSL_CONNECTING;
diff --git a/lib/stream-tcp.c b/lib/stream-tcp.c
index 2b57ca7..550c858 100644
--- a/lib/stream-tcp.c
+++ b/lib/stream-tcp.c
@@ -49,11 +49,12 @@ new_tcp_stream(const char *name, int fd, int connect_status,
 }

 static int
-tcp_open(const char *name, char *suffix, struct stream **streamp, uint8_t dscp)
+tcp_open(const char *name, char *suffix, const char *local,
+         struct stream **streamp, uint8_t dscp)
 {
     int fd, error;

-    error = inet_open_active(SOCK_STREAM, suffix, 0, NULL, &fd, dscp);
+    error = inet_open_active(SOCK_STREAM, suffix, 0, local, NULL, &fd, dscp);
     if (fd >= 0) {
         return new_tcp_stream(name, fd, error, streamp);
     } else {
@@ -79,8 +80,8 @@ const struct stream_class tcp_stream_class = {
 #include "dirs.h"

 static int
-windows_open(const char *name, char *suffix, struct stream **streamp,
-             uint8_t dscp)
+windows_open(const char *name, char *suffix, const char *local,
+             struct stream **streamp, uint8_t dscp)
 {
     int error, port;
     FILE *file;
@@ -112,7 +113,7 @@ windows_open(const char *name, char *suffix, struct stream **streamp,

     suffix_new = xasprintf("127.0.0.1:%d", port);

-    error = tcp_open(name, suffix_new, streamp, dscp);
+    error = tcp_open(name, suffix_new, local, streamp, dscp);

     free(suffix_new);
     free(path);
diff --git a/lib/stream-unix.c b/lib/stream-unix.c
index cadd180..7e743fc 100644
--- a/lib/stream-unix.c
+++ b/lib/stream-unix.c
@@ -40,11 +40,12 @@ VLOG_DEFINE_THIS_MODULE(stream_unix);
 /* Active UNIX socket. */

 static int
-unix_open(const char *name, char *suffix, struct stream **streamp,
-          uint8_t dscp OVS_UNUSED)
+unix_open(const char *name, char *suffix, const char *local,
+          struct stream **streamp, uint8_t dscp OVS_UNUSED)
 {
     char *connect_path;
     int fd;
+    (void)local;

     connect_path = abs_file_name(ovs_rundir(), suffix);
     fd = make_unix_socket(SOCK_STREAM, true, NULL, connect_path);
diff --git a/lib/stream.c b/lib/stream.c
index f6ea849..f85c63e 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -204,7 +204,8 @@ stream_verify_name(const char *name)
  * stores a pointer to the new connection in '*streamp', otherwise a null
  * pointer.  */
 int
-stream_open(const char *name, struct stream **streamp, uint8_t dscp)
+stream_open(const char *name, const char *local,
+            struct stream **streamp, uint8_t dscp)
 {
     const struct stream_class *class;
     struct stream *stream;
@@ -221,7 +222,7 @@ stream_open(const char *name, struct stream **streamp, uint8_t dscp)

     /* Call class's "open" function. */
     suffix_copy = xstrdup(strchr(name, ':') + 1);
-    error = class->open(name, suffix_copy, &stream, dscp);
+    error = class->open(name, suffix_copy, local, &stream, dscp);
     free(suffix_copy);
     if (error) {
         goto error;
@@ -667,6 +668,7 @@ count_fields(const char *s_)
  * number is given. */
 int
 stream_open_with_default_port(const char *name_,
+                              const char *local,
                               uint16_t default_port,
                               struct stream **streamp,
                               uint8_t dscp)
@@ -689,7 +691,7 @@ stream_open_with_default_port(const char *name_,
     } else {
         name = xstrdup(name_);
     }
-    error = stream_open(name, streamp, dscp);
+    error = stream_open(name, local, streamp, dscp);
     free(name);

     return error;
diff --git a/lib/stream.h b/lib/stream.h
index f8e1891..a3d63dc 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -33,7 +33,8 @@ void stream_usage(const char *name, bool active, bool passive, bool bootstrap);

 /* Bidirectional byte streams. */
 int stream_verify_name(const char *name);
-int stream_open(const char *name, struct stream **, uint8_t dscp);
+int stream_open(const char *name, const char *local,
+                struct stream **, uint8_t dscp);
 int stream_open_block(int error, struct stream **);
 void stream_close(struct stream *);
 const char *stream_get_name(const struct stream *);
@@ -68,6 +69,7 @@ ovs_be16 pstream_get_bound_port(const struct pstream *);
 /* Convenience functions. */

 int stream_open_with_default_port(const char *name,
+                                  const char *local,
                                   uint16_t default_port,
                                   struct stream **,
                                   uint8_t dscp);
diff --git a/lib/syslog-direct.c b/lib/syslog-direct.c
index 85ca9e2..eff7bb3 100644
--- a/lib/syslog-direct.c
+++ b/lib/syslog-direct.c
@@ -58,7 +58,7 @@ syslog_direct_create(const char *method)
      * so that deadlocks would be avoided.  The problem is that these
      * functions that create socket might call VLOG() */
     if (!strncmp(method, "udp:", 4)) {
-        inet_open_active(SOCK_DGRAM, &method[4], 514, NULL, &this->fd, 0);
+        inet_open_active(SOCK_DGRAM, &method[4], 514, NULL, NULL, &this->fd, 0);
     } else if (!strncmp(method, "unix:", 5)) {
         this->fd = make_unix_socket(SOCK_DGRAM, true, NULL, &method[5]);
     } else {
diff --git a/lib/unixctl.c b/lib/unixctl.c
index 935c145..bf1fd3c 100644
--- a/lib/unixctl.c
+++ b/lib/unixctl.c
@@ -463,7 +463,7 @@ unixctl_client_create(const char *path, struct jsonrpc **client)

     *client = NULL;

-    error = stream_open_block(stream_open(unix_path, &stream, DSCP_DEFAULT),
+    error = stream_open_block(stream_open(unix_path, NULL, &stream, DSCP_DEFAULT),
                               &stream);
     free(unix_path);
     free(abs_path);
diff --git a/lib/vconn-stream.c b/lib/vconn-stream.c
index 33f1388..3133716 100644
--- a/lib/vconn-stream.c
+++ b/lib/vconn-stream.c
@@ -78,7 +78,7 @@ vconn_stream_open(const char *name, uint32_t allowed_versions,
     struct stream *stream;
     int error;

-    error = stream_open_with_default_port(name, OFP_PORT, &stream, dscp);
+    error = stream_open_with_default_port(name, NULL, OFP_PORT, &stream, dscp);
     if (!error) {
         error = stream_connect(stream);
         if (!error || error == EAGAIN) {
diff --git a/lib/vlog.c b/lib/vlog.c
index 30b5bc2..45b179d 100644
--- a/lib/vlog.c
+++ b/lib/vlog.c
@@ -599,7 +599,7 @@ vlog_set_syslog_target(const char *target)
 {
     int new_fd;

-    inet_open_active(SOCK_DGRAM, target, 0, NULL, &new_fd, 0);
+    inet_open_active(SOCK_DGRAM, target, 0, NULL, NULL, &new_fd, 0);

     ovs_rwlock_wrlock(&pattern_rwlock);
     if (syslog_fd >= 0) {
diff --git a/ofproto/collectors.c b/ofproto/collectors.c
index 5b29212..c3cd755 100644
--- a/ofproto/collectors.c
+++ b/ofproto/collectors.c
@@ -63,7 +63,8 @@ collectors_create(const struct sset *targets, uint16_t default_port,
         int error;
         int fd;

-        error = inet_open_active(SOCK_DGRAM, name, default_port, NULL, &fd, 0);
+        error = inet_open_active(SOCK_DGRAM, name, default_port, NULL,
+                                 NULL, &fd, 0);
         if (fd >= 0) {
             c->fds[c->n_fds++] = fd;
         } else {
diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c
index f68f842..d6053ab 100644
--- a/ovn/controller/ovn-controller.c
+++ b/ovn/controller/ovn-controller.c
@@ -63,6 +63,7 @@ static void parse_options(int argc, char *argv[]);
 OVS_NO_RETURN static void usage(void);

 static char *ovs_remote;
+static char *local_address;

 struct local_datapath *
 get_local_datapath(const struct hmap *local_datapaths, uint32_t tunnel_key)
@@ -313,6 +314,7 @@ main(int argc, char *argv[])
     char *ovnsb_remote = get_ovnsb_remote(ovs_idl_loop.idl);
     struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
         ovsdb_idl_create(ovnsb_remote, &sbrec_idl_class, true, true));
+    ovsdb_idl_set_local(ovnsb_idl_loop.idl, local_address);
     ovsdb_idl_get_initial_snapshot(ovnsb_idl_loop.idl);

     int probe_interval = 0;
@@ -336,6 +338,7 @@ main(int argc, char *argv[])
             free(ovnsb_remote);
             ovnsb_remote = new_ovnsb_remote;
             ovsdb_idl_set_remote(ovnsb_idl_loop.idl, ovnsb_remote, true);
+            ovsdb_idl_set_local(ovnsb_idl_loop.idl, local_address);
         } else {
             free(new_ovnsb_remote);
         }
@@ -462,6 +465,7 @@ main(int argc, char *argv[])

     free(ovnsb_remote);
     free(ovs_remote);
+    free(local_address);
     service_stop();

     exit(retval);
@@ -480,6 +484,7 @@ parse_options(int argc, char *argv[])
     static struct option long_options[] = {
         {"help", no_argument, NULL, 'h'},
         {"version", no_argument, NULL, 'V'},
+        {"local-address", required_argument, NULL, 'l'},
         VLOG_LONG_OPTIONS,
         DAEMON_LONG_OPTIONS,
         STREAM_SSL_LONG_OPTIONS,
@@ -505,6 +510,10 @@ parse_options(int argc, char *argv[])
             ovs_print_version(OFP13_VERSION, OFP13_VERSION);
             exit(EXIT_SUCCESS);

+        case 'l':
+            local_address = xstrdup(optarg);
+            break;
+
         VLOG_OPTION_HANDLERS
         DAEMON_OPTION_HANDLERS
         STREAM_SSL_OPTION_HANDLERS
@@ -537,6 +546,14 @@ parse_options(int argc, char *argv[])
         VLOG_FATAL("exactly zero or one non-option argument required; "
                    "use --help for usage");
     }
+
+    if (local_address) {
+        struct sockaddr_storage ss;
+        if (!inet_parse_active(local_address, 0, &ss)) {
+            VLOG_FATAL("invalid local address %s; use --help for usage",
+                    local_address);
+        }
+    }
 }

 static void
@@ -551,7 +568,10 @@ usage(void)
     vlog_usage();
     printf("\nOther options:\n"
            "  -h, --help              display this help message\n"
-           "  -V, --version           display version information\n");
+           "  -V, --version           display version information\n"
+           "  -l, --local-address=IP:PORT\n"
+           "                          set the local address used for active "
+                                      "OVS-DATABASE connection\n");
     exit(EXIT_SUCCESS);
 }

diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c
index 80819a8..9fe935f 100644
--- a/ovsdb/ovsdb-client.c
+++ b/ovsdb/ovsdb-client.c
@@ -315,7 +315,7 @@ open_jsonrpc(const char *server)
     struct stream *stream;
     int error;

-    error = stream_open_block(jsonrpc_stream_open(server, &stream,
+    error = stream_open_block(jsonrpc_stream_open(server, NULL, &stream,
                               DSCP_DEFAULT), &stream);
     if (error == EAFNOSUPPORT) {
         struct pstream *pstream;
diff --git a/tests/test-jsonrpc.c b/tests/test-jsonrpc.c
index feac0b0..00d1030 100644
--- a/tests/test-jsonrpc.c
+++ b/tests/test-jsonrpc.c
@@ -270,7 +270,7 @@ do_request(struct ovs_cmdl_context *ctx)
         ovs_fatal(0, "not a valid JSON-RPC request: %s", string);
     }

-    error = stream_open_block(jsonrpc_stream_open(ctx->argv[1], &stream,
+    error = stream_open_block(jsonrpc_stream_open(ctx->argv[1], NULL, &stream,
                               DSCP_DEFAULT), &stream);
     if (error) {
         ovs_fatal(error, "could not open \"%s\"", ctx->argv[1]);
@@ -310,7 +310,7 @@ do_notify(struct ovs_cmdl_context *ctx)
         ovs_fatal(0, "not a JSON RPC-valid notification: %s", string);
     }

-    error = stream_open_block(jsonrpc_stream_open(ctx->argv[1], &stream,
+    error = stream_open_block(jsonrpc_stream_open(ctx->argv[1], NULL, &stream,
                               DSCP_DEFAULT), &stream);
     if (error) {
         ovs_fatal(error, "could not open \"%s\"", ctx->argv[1]);
diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c
index dbb6897..bcc05a0 100644
--- a/tests/test-ovsdb.c
+++ b/tests/test-ovsdb.c
@@ -2090,8 +2090,8 @@ do_idl(struct ovs_cmdl_context *ctx)
     if (ctx->argc > 2) {
         struct stream *stream;

-        error = stream_open_block(jsonrpc_stream_open(ctx->argv[1], &stream,
-                                  DSCP_DEFAULT), &stream);
+        error = stream_open_block(jsonrpc_stream_open(ctx->argv[1], NULL,
+                                  &stream, DSCP_DEFAULT), &stream);
         if (error) {
             ovs_fatal(error, "failed to connect to \"%s\"", ctx->argv[1]);
         }
--
1.9.1





More information about the dev mailing list