LCOV - code coverage report
Current view: top level - ovsdb - jsonrpc-server.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 507 653 77.6 %
Date: 2016-09-14 01:02:56 Functions: 56 62 90.3 %
Branches: 238 355 67.0 %

           Branch data     Line data    Source code
       1                 :            : /* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
       2                 :            :  *
       3                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       4                 :            :  * you may not use this file except in compliance with the License.
       5                 :            :  * You may obtain a copy of the License at:
       6                 :            :  *
       7                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       8                 :            :  *
       9                 :            :  * Unless required by applicable law or agreed to in writing, software
      10                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      11                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12                 :            :  * See the License for the specific language governing permissions and
      13                 :            :  * limitations under the License.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include <config.h>
      17                 :            : 
      18                 :            : #include "jsonrpc-server.h"
      19                 :            : 
      20                 :            : #include <errno.h>
      21                 :            : 
      22                 :            : #include "bitmap.h"
      23                 :            : #include "column.h"
      24                 :            : #include "openvswitch/dynamic-string.h"
      25                 :            : #include "monitor.h"
      26                 :            : #include "openvswitch/json.h"
      27                 :            : #include "jsonrpc.h"
      28                 :            : #include "ovsdb-error.h"
      29                 :            : #include "ovsdb-parser.h"
      30                 :            : #include "ovsdb.h"
      31                 :            : #include "condition.h"
      32                 :            : #include "poll-loop.h"
      33                 :            : #include "reconnect.h"
      34                 :            : #include "row.h"
      35                 :            : #include "server.h"
      36                 :            : #include "simap.h"
      37                 :            : #include "stream.h"
      38                 :            : #include "table.h"
      39                 :            : #include "timeval.h"
      40                 :            : #include "transaction.h"
      41                 :            : #include "trigger.h"
      42                 :            : #include "util.h"
      43                 :            : #include "openvswitch/vlog.h"
      44                 :            : 
      45                 :       2594 : VLOG_DEFINE_THIS_MODULE(ovsdb_jsonrpc_server);
      46                 :            : 
      47                 :            : struct ovsdb_jsonrpc_remote;
      48                 :            : struct ovsdb_jsonrpc_session;
      49                 :            : 
      50                 :            : /* Set false to defeature monitor_cond, causing jsonrpc to respond to
      51                 :            :  * monitor_cond method with an error.  */
      52                 :            : static bool monitor_cond_enable__ = true;
      53                 :            : 
      54                 :            : /* Message rate-limiting. */
      55                 :            : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
      56                 :            : 
      57                 :            : /* Sessions. */
      58                 :            : static struct ovsdb_jsonrpc_session *ovsdb_jsonrpc_session_create(
      59                 :            :     struct ovsdb_jsonrpc_remote *, struct jsonrpc_session *, bool);
      60                 :            : static void ovsdb_jsonrpc_session_run_all(struct ovsdb_jsonrpc_remote *);
      61                 :            : static void ovsdb_jsonrpc_session_wait_all(struct ovsdb_jsonrpc_remote *);
      62                 :            : static void ovsdb_jsonrpc_session_get_memory_usage_all(
      63                 :            :     const struct ovsdb_jsonrpc_remote *, struct simap *usage);
      64                 :            : static void ovsdb_jsonrpc_session_close_all(struct ovsdb_jsonrpc_remote *);
      65                 :            : static void ovsdb_jsonrpc_session_reconnect_all(struct ovsdb_jsonrpc_remote *);
      66                 :            : static void ovsdb_jsonrpc_session_set_all_options(
      67                 :            :     struct ovsdb_jsonrpc_remote *, const struct ovsdb_jsonrpc_options *);
      68                 :            : static bool ovsdb_jsonrpc_active_session_get_status(
      69                 :            :     const struct ovsdb_jsonrpc_remote *,
      70                 :            :     struct ovsdb_jsonrpc_remote_status *);
      71                 :            : static void ovsdb_jsonrpc_session_get_status(
      72                 :            :     const struct ovsdb_jsonrpc_session *,
      73                 :            :     struct ovsdb_jsonrpc_remote_status *);
      74                 :            : static void ovsdb_jsonrpc_session_unlock_all(struct ovsdb_jsonrpc_session *);
      75                 :            : static void ovsdb_jsonrpc_session_unlock__(struct ovsdb_lock_waiter *);
      76                 :            : static void ovsdb_jsonrpc_session_send(struct ovsdb_jsonrpc_session *,
      77                 :            :                                        struct jsonrpc_msg *);
      78                 :            : 
      79                 :            : /* Triggers. */
      80                 :            : static void ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session *,
      81                 :            :                                          struct ovsdb *,
      82                 :            :                                          struct json *id, struct json *params);
      83                 :            : static struct ovsdb_jsonrpc_trigger *ovsdb_jsonrpc_trigger_find(
      84                 :            :     struct ovsdb_jsonrpc_session *, const struct json *id, size_t hash);
      85                 :            : static void ovsdb_jsonrpc_trigger_complete(struct ovsdb_jsonrpc_trigger *);
      86                 :            : static void ovsdb_jsonrpc_trigger_complete_all(struct ovsdb_jsonrpc_session *);
      87                 :            : static void ovsdb_jsonrpc_trigger_complete_done(
      88                 :            :     struct ovsdb_jsonrpc_session *);
      89                 :            : 
      90                 :            : /* Monitors. */
      91                 :            : static struct jsonrpc_msg *ovsdb_jsonrpc_monitor_create(
      92                 :            :     struct ovsdb_jsonrpc_session *, struct ovsdb *, struct json *params,
      93                 :            :     enum ovsdb_monitor_version, const struct json *request_id);
      94                 :            : static struct jsonrpc_msg *ovsdb_jsonrpc_monitor_cond_change(
      95                 :            :     struct ovsdb_jsonrpc_session *s,
      96                 :            :     struct json *params,
      97                 :            :     const struct json *request_id);
      98                 :            : static struct jsonrpc_msg *ovsdb_jsonrpc_monitor_cancel(
      99                 :            :     struct ovsdb_jsonrpc_session *,
     100                 :            :     struct json_array *params,
     101                 :            :     const struct json *request_id);
     102                 :            : static void ovsdb_jsonrpc_monitor_remove_all(struct ovsdb_jsonrpc_session *);
     103                 :            : static void ovsdb_jsonrpc_monitor_flush_all(struct ovsdb_jsonrpc_session *);
     104                 :            : static bool ovsdb_jsonrpc_monitor_needs_flush(struct ovsdb_jsonrpc_session *);
     105                 :            : static struct json *ovsdb_jsonrpc_monitor_compose_update(
     106                 :            :     struct ovsdb_jsonrpc_monitor *monitor, bool initial);
     107                 :            : static struct jsonrpc_msg * ovsdb_jsonrpc_create_notify(
     108                 :            :                                         const struct ovsdb_jsonrpc_monitor *m,
     109                 :            :                                         struct json *params);
     110                 :            : 
     111                 :            : 
     112                 :            : /* JSON-RPC database server. */
     113                 :            : 
     114                 :            : struct ovsdb_jsonrpc_server {
     115                 :            :     struct ovsdb_server up;
     116                 :            :     unsigned int n_sessions;
     117                 :            :     bool read_only;            /* This server is does not accept any
     118                 :            :                                   transactions that can modify the database. */
     119                 :            :     struct shash remotes;      /* Contains "struct ovsdb_jsonrpc_remote *"s. */
     120                 :            : };
     121                 :            : 
     122                 :            : /* A configured remote.  This is either a passive stream listener plus a list
     123                 :            :  * of the currently connected sessions, or a list of exactly one active
     124                 :            :  * session. */
     125                 :            : struct ovsdb_jsonrpc_remote {
     126                 :            :     struct ovsdb_jsonrpc_server *server;
     127                 :            :     struct pstream *listener;   /* Listener, if passive. */
     128                 :            :     struct ovs_list sessions;   /* List of "struct ovsdb_jsonrpc_session"s. */
     129                 :            :     uint8_t dscp;
     130                 :            : };
     131                 :            : 
     132                 :            : static struct ovsdb_jsonrpc_remote *ovsdb_jsonrpc_server_add_remote(
     133                 :            :     struct ovsdb_jsonrpc_server *, const char *name,
     134                 :            :     const struct ovsdb_jsonrpc_options *options
     135                 :            : );
     136                 :            : static void ovsdb_jsonrpc_server_del_remote(struct shash_node *);
     137                 :            : 
     138                 :            : /* Creates and returns a new server to provide JSON-RPC access to an OVSDB.
     139                 :            :  *
     140                 :            :  * The caller must call ovsdb_jsonrpc_server_add_db() for each database to
     141                 :            :  * which 'server' should provide access. */
     142                 :            : struct ovsdb_jsonrpc_server *
     143                 :       1260 : ovsdb_jsonrpc_server_create(bool read_only)
     144                 :            : {
     145                 :       1260 :     struct ovsdb_jsonrpc_server *server = xzalloc(sizeof *server);
     146                 :       1260 :     ovsdb_server_init(&server->up);
     147                 :       1260 :     shash_init(&server->remotes);
     148                 :       1260 :     server->read_only = read_only;
     149                 :       1260 :     return server;
     150                 :            : }
     151                 :            : 
     152                 :            : /* Adds 'db' to the set of databases served out by 'svr'.  Returns true if
     153                 :            :  * successful, false if 'db''s name is the same as some database already in
     154                 :            :  * 'server'. */
     155                 :            : bool
     156                 :       1271 : ovsdb_jsonrpc_server_add_db(struct ovsdb_jsonrpc_server *svr, struct ovsdb *db)
     157                 :            : {
     158                 :            :     /* The OVSDB protocol doesn't have a way to notify a client that a
     159                 :            :      * database has been added.  If some client tried to use the database
     160                 :            :      * that we're adding and failed, then forcing it to reconnect seems like
     161                 :            :      * a reasonable way to make it try again.
     162                 :            :      *
     163                 :            :      * If this is too big of a hammer in practice, we could be more selective,
     164                 :            :      * e.g. disconnect only connections that actually tried to use a database
     165                 :            :      * with 'db''s name. */
     166                 :       1271 :     ovsdb_jsonrpc_server_reconnect(svr, svr->read_only);
     167                 :            : 
     168                 :       1271 :     return ovsdb_server_add_db(&svr->up, db);
     169                 :            : }
     170                 :            : 
     171                 :            : /* Removes 'db' from the set of databases served out by 'svr'.  Returns
     172                 :            :  * true if successful, false if there is no database associated with 'db'. */
     173                 :            : bool
     174                 :          2 : ovsdb_jsonrpc_server_remove_db(struct ovsdb_jsonrpc_server *svr,
     175                 :            :                                struct ovsdb *db)
     176                 :            : {
     177                 :            :     /* There might be pointers to 'db' from 'svr', such as monitors or
     178                 :            :      * outstanding transactions.  Disconnect all JSON-RPC connections to avoid
     179                 :            :      * accesses to freed memory.
     180                 :            :      *
     181                 :            :      * If this is too big of a hammer in practice, we could be more selective,
     182                 :            :      * e.g. disconnect only connections that actually reference 'db'. */
     183                 :          2 :     ovsdb_jsonrpc_server_reconnect(svr, svr->read_only);
     184                 :            : 
     185                 :          2 :     return ovsdb_server_remove_db(&svr->up, db);
     186                 :            : }
     187                 :            : 
     188                 :            : void
     189                 :       1258 : ovsdb_jsonrpc_server_destroy(struct ovsdb_jsonrpc_server *svr)
     190                 :            : {
     191                 :            :     struct shash_node *node, *next;
     192                 :            : 
     193 [ +  + ][ -  + ]:       2550 :     SHASH_FOR_EACH_SAFE (node, next, &svr->remotes) {
                 [ +  + ]
     194                 :       1292 :         ovsdb_jsonrpc_server_del_remote(node);
     195                 :            :     }
     196                 :       1258 :     shash_destroy(&svr->remotes);
     197                 :       1258 :     ovsdb_server_destroy(&svr->up);
     198                 :       1258 :     free(svr);
     199                 :       1258 : }
     200                 :            : 
     201                 :            : struct ovsdb_jsonrpc_options *
     202                 :      60869 : ovsdb_jsonrpc_default_options(const char *target)
     203                 :            : {
     204                 :      60869 :     struct ovsdb_jsonrpc_options *options = xzalloc(sizeof *options);
     205                 :      60869 :     options->max_backoff = RECONNECT_DEFAULT_MAX_BACKOFF;
     206                 :      60869 :     options->probe_interval = (stream_or_pstream_needs_probes(target)
     207                 :            :                                ? RECONNECT_DEFAULT_PROBE_INTERVAL
     208         [ +  + ]:      60869 :                                : 0);
     209                 :      60869 :     return options;
     210                 :            : }
     211                 :            : 
     212                 :            : /* Sets 'svr''s current set of remotes to the names in 'new_remotes', with
     213                 :            :  * options in the struct ovsdb_jsonrpc_options supplied as the data values.
     214                 :            :  *
     215                 :            :  * A remote is an active or passive stream connection method, e.g. "pssl:" or
     216                 :            :  * "tcp:1.2.3.4". */
     217                 :            : void
     218                 :      60264 : ovsdb_jsonrpc_server_set_remotes(struct ovsdb_jsonrpc_server *svr,
     219                 :            :                                  const struct shash *new_remotes)
     220                 :            : {
     221                 :            :     struct shash_node *node, *next;
     222                 :            : 
     223 [ +  + ][ -  + ]:     119841 :     SHASH_FOR_EACH_SAFE (node, next, &svr->remotes) {
                 [ +  + ]
     224                 :      59577 :         struct ovsdb_jsonrpc_remote *remote = node->data;
     225                 :      59577 :         struct ovsdb_jsonrpc_options *options
     226                 :      59577 :             = shash_find_data(new_remotes, node->name);
     227                 :            : 
     228         [ +  + ]:      59577 :         if (!options) {
     229         [ +  - ]:          2 :             VLOG_INFO("%s: remote deconfigured", node->name);
     230                 :          2 :             ovsdb_jsonrpc_server_del_remote(node);
     231         [ -  + ]:      59575 :         } else if (options->dscp != remote->dscp) {
     232                 :          0 :             ovsdb_jsonrpc_server_del_remote(node);
     233                 :            :          }
     234                 :            :     }
     235 [ +  + ][ -  + ]:     121133 :     SHASH_FOR_EACH (node, new_remotes) {
     236                 :      60869 :         const struct ovsdb_jsonrpc_options *options = node->data;
     237                 :            :         struct ovsdb_jsonrpc_remote *remote;
     238                 :            : 
     239                 :      60869 :         remote = shash_find_data(&svr->remotes, node->name);
     240         [ +  + ]:      60869 :         if (!remote) {
     241                 :       1294 :             remote = ovsdb_jsonrpc_server_add_remote(svr, node->name, options);
     242         [ -  + ]:       1294 :             if (!remote) {
     243                 :          0 :                 continue;
     244                 :            :             }
     245                 :            :         }
     246                 :            : 
     247                 :      60869 :         ovsdb_jsonrpc_session_set_all_options(remote, options);
     248                 :            :     }
     249                 :      60264 : }
     250                 :            : 
     251                 :            : static struct ovsdb_jsonrpc_remote *
     252                 :       1294 : ovsdb_jsonrpc_server_add_remote(struct ovsdb_jsonrpc_server *svr,
     253                 :            :                                 const char *name,
     254                 :            :                                 const struct ovsdb_jsonrpc_options *options)
     255                 :            : {
     256                 :            :     struct ovsdb_jsonrpc_remote *remote;
     257                 :            :     struct pstream *listener;
     258                 :            :     int error;
     259                 :            : 
     260                 :       1294 :     error = jsonrpc_pstream_open(name, &listener, options->dscp);
     261 [ +  + ][ -  + ]:       1294 :     if (error && error != EAFNOSUPPORT) {
     262         [ #  # ]:          0 :         VLOG_ERR_RL(&rl, "%s: listen failed: %s", name, ovs_strerror(error));
     263                 :          0 :         return NULL;
     264                 :            :     }
     265                 :            : 
     266                 :       1294 :     remote = xmalloc(sizeof *remote);
     267                 :       1294 :     remote->server = svr;
     268                 :       1294 :     remote->listener = listener;
     269                 :       1294 :     ovs_list_init(&remote->sessions);
     270                 :       1294 :     remote->dscp = options->dscp;
     271                 :       1294 :     shash_add(&svr->remotes, name, remote);
     272                 :            : 
     273         [ +  + ]:       1294 :     if (!listener) {
     274                 :          1 :         ovsdb_jsonrpc_session_create(remote, jsonrpc_session_open(name, true),
     275                 :          1 :                                       svr->read_only);
     276                 :            :     }
     277                 :       1294 :     return remote;
     278                 :            : }
     279                 :            : 
     280                 :            : static void
     281                 :       1294 : ovsdb_jsonrpc_server_del_remote(struct shash_node *node)
     282                 :            : {
     283                 :       1294 :     struct ovsdb_jsonrpc_remote *remote = node->data;
     284                 :            : 
     285                 :       1294 :     ovsdb_jsonrpc_session_close_all(remote);
     286                 :       1294 :     pstream_close(remote->listener);
     287                 :       1294 :     shash_delete(&remote->server->remotes, node);
     288                 :       1294 :     free(remote);
     289                 :       1294 : }
     290                 :            : 
     291                 :            : /* Stores status information for the remote named 'target', which should have
     292                 :            :  * been configured on 'svr' with a call to ovsdb_jsonrpc_server_set_remotes(),
     293                 :            :  * into '*status'.  On success returns true, on failure (if 'svr' doesn't have
     294                 :            :  * a remote named 'target' or if that remote is an outbound remote that has no
     295                 :            :  * active connections) returns false.  On failure, 'status' will be zeroed.
     296                 :            :  */
     297                 :            : bool
     298                 :          1 : ovsdb_jsonrpc_server_get_remote_status(
     299                 :            :     const struct ovsdb_jsonrpc_server *svr, const char *target,
     300                 :            :     struct ovsdb_jsonrpc_remote_status *status)
     301                 :            : {
     302                 :            :     const struct ovsdb_jsonrpc_remote *remote;
     303                 :            : 
     304                 :          1 :     memset(status, 0, sizeof *status);
     305                 :            : 
     306                 :          1 :     remote = shash_find_data(&svr->remotes, target);
     307                 :            : 
     308         [ -  + ]:          1 :     if (!remote) {
     309                 :          0 :         return false;
     310                 :            :     }
     311                 :            : 
     312         [ +  - ]:          1 :     if (remote->listener) {
     313                 :          1 :         status->bound_port = pstream_get_bound_port(remote->listener);
     314                 :          1 :         status->is_connected = !ovs_list_is_empty(&remote->sessions);
     315                 :          1 :         status->n_connections = ovs_list_size(&remote->sessions);
     316                 :          1 :         return true;
     317                 :            :     }
     318                 :            : 
     319                 :          0 :     return ovsdb_jsonrpc_active_session_get_status(remote, status);
     320                 :            : }
     321                 :            : 
     322                 :            : void
     323                 :          1 : ovsdb_jsonrpc_server_free_remote_status(
     324                 :            :     struct ovsdb_jsonrpc_remote_status *status)
     325                 :            : {
     326                 :          1 :     free(status->locks_held);
     327                 :          1 :     free(status->locks_waiting);
     328                 :          1 :     free(status->locks_lost);
     329                 :          1 : }
     330                 :            : 
     331                 :            : /* Forces all of the JSON-RPC sessions managed by 'svr' to disconnect and
     332                 :            :  * reconnect. */
     333                 :            : void
     334                 :       1277 : ovsdb_jsonrpc_server_reconnect(struct ovsdb_jsonrpc_server *svr, bool read_only)
     335                 :            : {
     336                 :            :     struct shash_node *node;
     337                 :            : 
     338                 :       1277 :     svr->read_only = read_only;
     339 [ +  + ][ -  + ]:       1286 :     SHASH_FOR_EACH (node, &svr->remotes) {
     340                 :          9 :         struct ovsdb_jsonrpc_remote *remote = node->data;
     341                 :            : 
     342                 :          9 :         ovsdb_jsonrpc_session_reconnect_all(remote);
     343                 :            :     }
     344                 :       1277 : }
     345                 :            : 
     346                 :            : bool
     347                 :          2 : ovsdb_jsonrpc_server_is_read_only(struct ovsdb_jsonrpc_server *svr)
     348                 :            : {
     349                 :          2 :     return svr->read_only;
     350                 :            : }
     351                 :            : 
     352                 :            : void
     353                 :      59004 : ovsdb_jsonrpc_server_run(struct ovsdb_jsonrpc_server *svr)
     354                 :            : {
     355                 :            :     struct shash_node *node;
     356                 :            : 
     357 [ +  + ][ -  + ]:     118581 :     SHASH_FOR_EACH (node, &svr->remotes) {
     358                 :      59577 :         struct ovsdb_jsonrpc_remote *remote = node->data;
     359                 :            : 
     360         [ +  + ]:      59577 :         if (remote->listener) {
     361                 :            :             struct stream *stream;
     362                 :            :             int error;
     363                 :            : 
     364                 :      59568 :             error = pstream_accept(remote->listener, &stream);
     365         [ +  + ]:      59568 :             if (!error) {
     366                 :            :                 struct jsonrpc_session *js;
     367                 :       8186 :                 js = jsonrpc_session_open_unreliably(jsonrpc_open(stream),
     368                 :       8186 :                                                      remote->dscp);
     369                 :       8186 :                 ovsdb_jsonrpc_session_create(remote, js, svr->read_only);
     370         [ -  + ]:      51382 :             } else if (error != EAGAIN) {
     371         [ #  # ]:      59568 :                 VLOG_WARN_RL(&rl, "%s: accept failed: %s",
     372                 :            :                              pstream_get_name(remote->listener),
     373                 :            :                              ovs_strerror(error));
     374                 :            :             }
     375                 :            :         }
     376                 :            : 
     377                 :      59577 :         ovsdb_jsonrpc_session_run_all(remote);
     378                 :            :     }
     379                 :      59004 : }
     380                 :            : 
     381                 :            : void
     382                 :      59004 : ovsdb_jsonrpc_server_wait(struct ovsdb_jsonrpc_server *svr)
     383                 :            : {
     384                 :            :     struct shash_node *node;
     385                 :            : 
     386 [ +  + ][ -  + ]:     118581 :     SHASH_FOR_EACH (node, &svr->remotes) {
     387                 :      59577 :         struct ovsdb_jsonrpc_remote *remote = node->data;
     388                 :            : 
     389         [ +  + ]:      59577 :         if (remote->listener) {
     390                 :      59568 :             pstream_wait(remote->listener);
     391                 :            :         }
     392                 :            : 
     393                 :      59577 :         ovsdb_jsonrpc_session_wait_all(remote);
     394                 :            :     }
     395                 :      59004 : }
     396                 :            : 
     397                 :            : /* Adds some memory usage statistics for 'svr' into 'usage', for use with
     398                 :            :  * memory_report(). */
     399                 :            : void
     400                 :         72 : ovsdb_jsonrpc_server_get_memory_usage(const struct ovsdb_jsonrpc_server *svr,
     401                 :            :                                       struct simap *usage)
     402                 :            : {
     403                 :            :     struct shash_node *node;
     404                 :            : 
     405                 :         72 :     simap_increase(usage, "sessions", svr->n_sessions);
     406 [ +  + ][ -  + ]:        144 :     SHASH_FOR_EACH (node, &svr->remotes) {
     407                 :         72 :         struct ovsdb_jsonrpc_remote *remote = node->data;
     408                 :            : 
     409                 :         72 :         ovsdb_jsonrpc_session_get_memory_usage_all(remote, usage);
     410                 :            :     }
     411                 :         72 : }
     412                 :            : 
     413                 :            : /* JSON-RPC database server session. */
     414                 :            : 
     415                 :            : struct ovsdb_jsonrpc_session {
     416                 :            :     struct ovs_list node;       /* Element in remote's sessions list. */
     417                 :            :     struct ovsdb_session up;
     418                 :            :     struct ovsdb_jsonrpc_remote *remote;
     419                 :            : 
     420                 :            :     /* Triggers. */
     421                 :            :     struct hmap triggers;       /* Hmap of "struct ovsdb_jsonrpc_trigger"s. */
     422                 :            : 
     423                 :            :     /* Monitors. */
     424                 :            :     struct hmap monitors;       /* Hmap of "struct ovsdb_jsonrpc_monitor"s. */
     425                 :            : 
     426                 :            :     /* Network connectivity. */
     427                 :            :     struct jsonrpc_session *js;  /* JSON-RPC session. */
     428                 :            :     unsigned int js_seqno;       /* Last jsonrpc_session_get_seqno() value. */
     429                 :            : 
     430                 :            :     /* Read only. */
     431                 :            :     bool read_only;             /*  When true, not allow to modify the
     432                 :            :                                     database. */
     433                 :            : };
     434                 :            : 
     435                 :            : static void ovsdb_jsonrpc_session_close(struct ovsdb_jsonrpc_session *);
     436                 :            : static int ovsdb_jsonrpc_session_run(struct ovsdb_jsonrpc_session *);
     437                 :            : static void ovsdb_jsonrpc_session_wait(struct ovsdb_jsonrpc_session *);
     438                 :            : static void ovsdb_jsonrpc_session_get_memory_usage(
     439                 :            :     const struct ovsdb_jsonrpc_session *, struct simap *usage);
     440                 :            : static void ovsdb_jsonrpc_session_got_request(struct ovsdb_jsonrpc_session *,
     441                 :            :                                               struct jsonrpc_msg *);
     442                 :            : static void ovsdb_jsonrpc_session_got_notify(struct ovsdb_jsonrpc_session *,
     443                 :            :                                              struct jsonrpc_msg *);
     444                 :            : 
     445                 :            : static struct ovsdb_jsonrpc_session *
     446                 :       8187 : ovsdb_jsonrpc_session_create(struct ovsdb_jsonrpc_remote *remote,
     447                 :            :                              struct jsonrpc_session *js, bool read_only)
     448                 :            : {
     449                 :            :     struct ovsdb_jsonrpc_session *s;
     450                 :            : 
     451                 :       8187 :     s = xzalloc(sizeof *s);
     452                 :       8187 :     ovsdb_session_init(&s->up, &remote->server->up);
     453                 :       8187 :     s->remote = remote;
     454                 :       8187 :     ovs_list_push_back(&remote->sessions, &s->node);
     455                 :       8187 :     hmap_init(&s->triggers);
     456                 :       8187 :     hmap_init(&s->monitors);
     457                 :       8187 :     s->js = js;
     458                 :       8187 :     s->js_seqno = jsonrpc_session_get_seqno(js);
     459                 :       8187 :     s->read_only = read_only;
     460                 :            : 
     461                 :       8187 :     remote->server->n_sessions++;
     462                 :            : 
     463                 :       8187 :     return s;
     464                 :            : }
     465                 :            : 
     466                 :            : static void
     467                 :       8187 : ovsdb_jsonrpc_session_close(struct ovsdb_jsonrpc_session *s)
     468                 :            : {
     469                 :       8187 :     ovsdb_jsonrpc_monitor_remove_all(s);
     470                 :       8187 :     ovsdb_jsonrpc_session_unlock_all(s);
     471                 :       8187 :     ovsdb_jsonrpc_trigger_complete_all(s);
     472                 :            : 
     473                 :       8187 :     hmap_destroy(&s->monitors);
     474                 :       8187 :     hmap_destroy(&s->triggers);
     475                 :            : 
     476                 :       8187 :     jsonrpc_session_close(s->js);
     477                 :       8187 :     ovs_list_remove(&s->node);
     478                 :       8187 :     s->remote->server->n_sessions--;
     479                 :       8187 :     ovsdb_session_destroy(&s->up);
     480                 :       8187 :     free(s);
     481                 :       8187 : }
     482                 :            : 
     483                 :            : static int
     484                 :      95115 : ovsdb_jsonrpc_session_run(struct ovsdb_jsonrpc_session *s)
     485                 :            : {
     486                 :      95115 :     jsonrpc_session_run(s->js);
     487         [ +  + ]:      95115 :     if (s->js_seqno != jsonrpc_session_get_seqno(s->js)) {
     488                 :       8058 :         s->js_seqno = jsonrpc_session_get_seqno(s->js);
     489                 :       8058 :         ovsdb_jsonrpc_trigger_complete_all(s);
     490                 :       8058 :         ovsdb_jsonrpc_monitor_remove_all(s);
     491                 :       8058 :         ovsdb_jsonrpc_session_unlock_all(s);
     492                 :            :     }
     493                 :            : 
     494                 :      95115 :     ovsdb_jsonrpc_trigger_complete_done(s);
     495                 :            : 
     496         [ +  + ]:      95115 :     if (!jsonrpc_session_get_backlog(s->js)) {
     497                 :            :         struct jsonrpc_msg *msg;
     498                 :            : 
     499                 :      94873 :         ovsdb_jsonrpc_monitor_flush_all(s);
     500                 :            : 
     501                 :      94873 :         msg = jsonrpc_session_recv(s->js);
     502         [ +  + ]:      94873 :         if (msg) {
     503         [ +  - ]:      27454 :             if (msg->type == JSONRPC_REQUEST) {
     504                 :      27454 :                 ovsdb_jsonrpc_session_got_request(s, msg);
     505         [ #  # ]:          0 :             } else if (msg->type == JSONRPC_NOTIFY) {
     506                 :          0 :                 ovsdb_jsonrpc_session_got_notify(s, msg);
     507                 :            :             } else {
     508         [ #  # ]:          0 :                 VLOG_WARN("%s: received unexpected %s message",
     509                 :            :                           jsonrpc_session_get_name(s->js),
     510                 :            :                           jsonrpc_msg_type_to_string(msg->type));
     511                 :          0 :                 jsonrpc_session_force_reconnect(s->js);
     512                 :          0 :                 jsonrpc_msg_destroy(msg);
     513                 :            :             }
     514                 :            :         }
     515                 :            :     }
     516         [ +  + ]:      95115 :     return jsonrpc_session_is_alive(s->js) ? 0 : ETIMEDOUT;
     517                 :            : }
     518                 :            : 
     519                 :            : static void
     520                 :      86930 : ovsdb_jsonrpc_session_set_options(struct ovsdb_jsonrpc_session *session,
     521                 :            :                                   const struct ovsdb_jsonrpc_options *options)
     522                 :            : {
     523                 :      86930 :     jsonrpc_session_set_max_backoff(session->js, options->max_backoff);
     524                 :      86930 :     jsonrpc_session_set_probe_interval(session->js, options->probe_interval);
     525                 :      86930 :     jsonrpc_session_set_dscp(session->js, options->dscp);
     526                 :      86930 : }
     527                 :            : 
     528                 :            : static void
     529                 :      59577 : ovsdb_jsonrpc_session_run_all(struct ovsdb_jsonrpc_remote *remote)
     530                 :            : {
     531                 :            :     struct ovsdb_jsonrpc_session *s, *next;
     532                 :            : 
     533 [ +  + ][ +  + ]:     154692 :     LIST_FOR_EACH_SAFE (s, next, node, &remote->sessions) {
     534                 :      95115 :         int error = ovsdb_jsonrpc_session_run(s);
     535         [ +  + ]:      95115 :         if (error) {
     536                 :       8055 :             ovsdb_jsonrpc_session_close(s);
     537                 :            :         }
     538                 :            :     }
     539                 :      59577 : }
     540                 :            : 
     541                 :            : static void
     542                 :      87060 : ovsdb_jsonrpc_session_wait(struct ovsdb_jsonrpc_session *s)
     543                 :            : {
     544                 :      87060 :     jsonrpc_session_wait(s->js);
     545         [ +  + ]:      87060 :     if (!jsonrpc_session_get_backlog(s->js)) {
     546         [ +  + ]:      86817 :         if (ovsdb_jsonrpc_monitor_needs_flush(s)) {
     547                 :       3840 :             poll_immediate_wake();
     548                 :            :         } else {
     549                 :      82977 :             jsonrpc_session_recv_wait(s->js);
     550                 :            :         }
     551                 :            :     }
     552                 :      87060 : }
     553                 :            : 
     554                 :            : static void
     555                 :      59577 : ovsdb_jsonrpc_session_wait_all(struct ovsdb_jsonrpc_remote *remote)
     556                 :            : {
     557                 :            :     struct ovsdb_jsonrpc_session *s;
     558                 :            : 
     559         [ +  + ]:     146637 :     LIST_FOR_EACH (s, node, &remote->sessions) {
     560                 :      87060 :         ovsdb_jsonrpc_session_wait(s);
     561                 :            :     }
     562                 :      59577 : }
     563                 :            : 
     564                 :            : static void
     565                 :        102 : ovsdb_jsonrpc_session_get_memory_usage(const struct ovsdb_jsonrpc_session *s,
     566                 :            :                                        struct simap *usage)
     567                 :            : {
     568                 :        102 :     simap_increase(usage, "triggers", hmap_count(&s->triggers));
     569                 :        102 :     simap_increase(usage, "backlog", jsonrpc_session_get_backlog(s->js));
     570                 :        102 : }
     571                 :            : 
     572                 :            : static void
     573                 :         72 : ovsdb_jsonrpc_session_get_memory_usage_all(
     574                 :            :     const struct ovsdb_jsonrpc_remote *remote,
     575                 :            :     struct simap *usage)
     576                 :            : {
     577                 :            :     struct ovsdb_jsonrpc_session *s;
     578                 :            : 
     579         [ +  + ]:        174 :     LIST_FOR_EACH (s, node, &remote->sessions) {
     580                 :        102 :         ovsdb_jsonrpc_session_get_memory_usage(s, usage);
     581                 :            :     }
     582                 :         72 : }
     583                 :            : 
     584                 :            : static void
     585                 :       1294 : ovsdb_jsonrpc_session_close_all(struct ovsdb_jsonrpc_remote *remote)
     586                 :            : {
     587                 :            :     struct ovsdb_jsonrpc_session *s, *next;
     588                 :            : 
     589 [ +  + ][ +  + ]:       1426 :     LIST_FOR_EACH_SAFE (s, next, node, &remote->sessions) {
     590                 :        132 :         ovsdb_jsonrpc_session_close(s);
     591                 :            :     }
     592                 :       1294 : }
     593                 :            : 
     594                 :            : /* Forces all of the JSON-RPC sessions managed by 'remote' to disconnect and
     595                 :            :  * reconnect. */
     596                 :            : static void
     597                 :          9 : ovsdb_jsonrpc_session_reconnect_all(struct ovsdb_jsonrpc_remote *remote)
     598                 :            : {
     599                 :            :     struct ovsdb_jsonrpc_session *s, *next;
     600                 :            : 
     601 [ +  + ][ +  + ]:         11 :     LIST_FOR_EACH_SAFE (s, next, node, &remote->sessions) {
     602                 :          2 :         jsonrpc_session_force_reconnect(s->js);
     603         [ -  + ]:          2 :         if (!jsonrpc_session_is_alive(s->js)) {
     604                 :          0 :             ovsdb_jsonrpc_session_close(s);
     605                 :            :         }
     606                 :            :     }
     607                 :          9 : }
     608                 :            : 
     609                 :            : /* Sets the options for all of the JSON-RPC sessions managed by 'remote' to
     610                 :            :  * 'options'.
     611                 :            :  *
     612                 :            :  * (The dscp value can't be changed directly; the caller must instead close and
     613                 :            :  * re-open the session.) */
     614                 :            : static void
     615                 :      60869 : ovsdb_jsonrpc_session_set_all_options(
     616                 :            :     struct ovsdb_jsonrpc_remote *remote,
     617                 :            :     const struct ovsdb_jsonrpc_options *options)
     618                 :            : {
     619                 :            :     struct ovsdb_jsonrpc_session *s;
     620                 :            : 
     621         [ +  + ]:     147799 :     LIST_FOR_EACH (s, node, &remote->sessions) {
     622                 :      86930 :         ovsdb_jsonrpc_session_set_options(s, options);
     623                 :            :     }
     624                 :      60869 : }
     625                 :            : 
     626                 :            : /* Sets the 'status' of for the 'remote' with an outgoing connection.   */
     627                 :            : static bool
     628                 :          0 : ovsdb_jsonrpc_active_session_get_status(
     629                 :            :     const struct ovsdb_jsonrpc_remote *remote,
     630                 :            :     struct ovsdb_jsonrpc_remote_status *status)
     631                 :            : {
     632                 :          0 :     const struct ovs_list *sessions = &remote->sessions;
     633                 :            :     const struct ovsdb_jsonrpc_session *s;
     634                 :            : 
     635         [ #  # ]:          0 :     if (ovs_list_is_empty(sessions)) {
     636                 :          0 :         return false;
     637                 :            :     }
     638                 :            : 
     639         [ #  # ]:          0 :     ovs_assert(ovs_list_is_singleton(sessions));
     640                 :          0 :     s = CONTAINER_OF(ovs_list_front(sessions), struct ovsdb_jsonrpc_session, node);
     641                 :          0 :     ovsdb_jsonrpc_session_get_status(s, status);
     642                 :          0 :     status->n_connections = 1;
     643                 :            : 
     644                 :          0 :     return true;
     645                 :            : }
     646                 :            : 
     647                 :            : static void
     648                 :          0 : ovsdb_jsonrpc_session_get_status(const struct ovsdb_jsonrpc_session *session,
     649                 :            :                                  struct ovsdb_jsonrpc_remote_status *status)
     650                 :            : {
     651                 :          0 :     const struct ovsdb_jsonrpc_session *s = session;
     652                 :            :     const struct jsonrpc_session *js;
     653                 :            :     struct ovsdb_lock_waiter *waiter;
     654                 :            :     struct reconnect_stats rstats;
     655                 :            :     struct ds locks_held, locks_waiting, locks_lost;
     656                 :            : 
     657                 :          0 :     js = s->js;
     658                 :            : 
     659                 :          0 :     status->is_connected = jsonrpc_session_is_connected(js);
     660                 :          0 :     status->last_error = jsonrpc_session_get_status(js);
     661                 :            : 
     662                 :          0 :     jsonrpc_session_get_reconnect_stats(js, &rstats);
     663                 :          0 :     status->state = rstats.state;
     664                 :          0 :     status->sec_since_connect = rstats.msec_since_connect == UINT_MAX
     665         [ #  # ]:          0 :         ? UINT_MAX : rstats.msec_since_connect / 1000;
     666                 :          0 :     status->sec_since_disconnect = rstats.msec_since_disconnect == UINT_MAX
     667         [ #  # ]:          0 :         ? UINT_MAX : rstats.msec_since_disconnect / 1000;
     668                 :            : 
     669                 :          0 :     ds_init(&locks_held);
     670                 :          0 :     ds_init(&locks_waiting);
     671                 :          0 :     ds_init(&locks_lost);
     672 [ #  # ][ #  # ]:          0 :     HMAP_FOR_EACH (waiter, session_node, &s->up.waiters) {
     673                 :            :         struct ds *string;
     674                 :            : 
     675                 :          0 :         string = (ovsdb_lock_waiter_is_owner(waiter) ? &locks_held
     676         [ #  # ]:          0 :                   : waiter->mode == OVSDB_LOCK_WAIT ? &locks_waiting
     677         [ #  # ]:          0 :                   : &locks_lost);
     678         [ #  # ]:          0 :         if (string->length) {
     679                 :          0 :             ds_put_char(string, ' ');
     680                 :            :         }
     681                 :          0 :         ds_put_cstr(string, waiter->lock_name);
     682                 :            :     }
     683                 :          0 :     status->locks_held = ds_steal_cstr(&locks_held);
     684                 :          0 :     status->locks_waiting = ds_steal_cstr(&locks_waiting);
     685                 :          0 :     status->locks_lost = ds_steal_cstr(&locks_lost);
     686                 :          0 : }
     687                 :            : 
     688                 :            : /* Examines 'request' to determine the database to which it relates, and then
     689                 :            :  * searches 's' to find that database:
     690                 :            :  *
     691                 :            :  *    - If successful, returns the database and sets '*replyp' to NULL.
     692                 :            :  *
     693                 :            :  *    - If no such database exists, returns NULL and sets '*replyp' to an
     694                 :            :  *      appropriate JSON-RPC error reply, owned by the caller. */
     695                 :            : static struct ovsdb *
     696                 :      26466 : ovsdb_jsonrpc_lookup_db(const struct ovsdb_jsonrpc_session *s,
     697                 :            :                         const struct jsonrpc_msg *request,
     698                 :            :                         struct jsonrpc_msg **replyp)
     699                 :            : {
     700                 :            :     struct json_array *params;
     701                 :            :     struct ovsdb_error *error;
     702                 :            :     const char *db_name;
     703                 :            :     struct ovsdb *db;
     704                 :            : 
     705                 :      26466 :     params = json_array(request->params);
     706 [ +  - ][ -  + ]:      26466 :     if (!params->n || params->elems[0]->type != JSON_STRING) {
     707                 :          0 :         error = ovsdb_syntax_error(
     708                 :          0 :             request->params, NULL,
     709                 :            :             "%s request params must begin with <db-name>", request->method);
     710                 :          0 :         goto error;
     711                 :            :     }
     712                 :            : 
     713                 :      26466 :     db_name = params->elems[0]->u.string;
     714                 :      26466 :     db = shash_find_data(&s->up.server->dbs, db_name);
     715         [ +  + ]:      26466 :     if (!db) {
     716                 :          1 :         error = ovsdb_syntax_error(
     717                 :          1 :             request->params, "unknown database",
     718                 :            :             "%s request specifies unknown database %s",
     719                 :            :             request->method, db_name);
     720                 :          1 :         goto error;
     721                 :            :     }
     722                 :            : 
     723                 :      26465 :     *replyp = NULL;
     724                 :      26465 :     return db;
     725                 :            : 
     726                 :            : error:
     727                 :          1 :     *replyp = jsonrpc_create_error(ovsdb_error_to_json(error), request->id);
     728                 :          1 :     ovsdb_error_destroy(error);
     729                 :          1 :     return NULL;
     730                 :            : }
     731                 :            : 
     732                 :            : static struct ovsdb_error *
     733                 :        638 : ovsdb_jsonrpc_session_parse_lock_name(const struct jsonrpc_msg *request,
     734                 :            :                                       const char **lock_namep)
     735                 :            : {
     736                 :            :     const struct json_array *params;
     737                 :            : 
     738                 :        638 :     params = json_array(request->params);
     739         [ +  - ]:       1276 :     if (params->n != 1 || params->elems[0]->type != JSON_STRING ||
           [ +  -  -  + ]
     740                 :        638 :         !ovsdb_parser_is_id(json_string(params->elems[0]))) {
     741                 :          0 :         *lock_namep = NULL;
     742                 :          0 :         return ovsdb_syntax_error(request->params, NULL,
     743                 :            :                                   "%s request params must be <id>",
     744                 :            :                                   request->method);
     745                 :            :     }
     746                 :            : 
     747                 :        638 :     *lock_namep = json_string(params->elems[0]);
     748                 :        638 :     return NULL;
     749                 :            : }
     750                 :            : 
     751                 :            : static void
     752                 :          4 : ovsdb_jsonrpc_session_notify(struct ovsdb_session *session,
     753                 :            :                              const char *lock_name,
     754                 :            :                              const char *method)
     755                 :            : {
     756                 :            :     struct ovsdb_jsonrpc_session *s;
     757                 :            :     struct json *params;
     758                 :            : 
     759                 :          4 :     s = CONTAINER_OF(session, struct ovsdb_jsonrpc_session, up);
     760                 :          4 :     params = json_array_create_1(json_string_create(lock_name));
     761                 :          4 :     ovsdb_jsonrpc_session_send(s, jsonrpc_create_notify(method, params));
     762                 :          4 : }
     763                 :            : 
     764                 :            : static struct jsonrpc_msg *
     765                 :          0 : jsonrpc_create_readonly_lock_error(const struct json *id)
     766                 :            : {
     767                 :          0 :     return jsonrpc_create_error(json_string_create(
     768                 :            :             "lock and unlock methods not allowed,"
     769                 :            :             " DB server is read only."), id);
     770                 :            : }
     771                 :            : 
     772                 :            : static struct jsonrpc_msg *
     773                 :        636 : ovsdb_jsonrpc_session_lock(struct ovsdb_jsonrpc_session *s,
     774                 :            :                            struct jsonrpc_msg *request,
     775                 :            :                            enum ovsdb_lock_mode mode)
     776                 :            : {
     777                 :            :     struct ovsdb_lock_waiter *waiter;
     778                 :            :     struct jsonrpc_msg *reply;
     779                 :            :     struct ovsdb_error *error;
     780                 :            :     struct ovsdb_session *victim;
     781                 :            :     const char *lock_name;
     782                 :            :     struct json *result;
     783                 :            : 
     784         [ -  + ]:        636 :     if (s->read_only) {
     785                 :          0 :         return jsonrpc_create_readonly_lock_error(request->id);
     786                 :            :     }
     787                 :            : 
     788                 :        636 :     error = ovsdb_jsonrpc_session_parse_lock_name(request, &lock_name);
     789         [ -  + ]:        636 :     if (error) {
     790                 :          0 :         goto error;
     791                 :            :     }
     792                 :            : 
     793                 :            :     /* Report error if this session has issued a "lock" or "steal" without a
     794                 :            :      * matching "unlock" for this lock. */
     795                 :        636 :     waiter = ovsdb_session_get_lock_waiter(&s->up, lock_name);
     796         [ -  + ]:        636 :     if (waiter) {
     797                 :          0 :         error = ovsdb_syntax_error(
     798                 :          0 :             request->params, NULL,
     799                 :            :             "must issue \"unlock\" before new \"%s\"", request->method);
     800                 :          0 :         goto error;
     801                 :            :     }
     802                 :            : 
     803                 :            :     /* Get the lock, add us as a waiter. */
     804                 :        636 :     waiter = ovsdb_server_lock(&s->remote->server->up, &s->up, lock_name, mode,
     805                 :            :                                &victim);
     806         [ +  + ]:        636 :     if (victim) {
     807                 :          1 :         ovsdb_jsonrpc_session_notify(victim, lock_name, "stolen");
     808                 :            :     }
     809                 :            : 
     810                 :        636 :     result = json_object_create();
     811                 :        636 :     json_object_put(result, "locked",
     812                 :        636 :                     json_boolean_create(ovsdb_lock_waiter_is_owner(waiter)));
     813                 :            : 
     814                 :        636 :     return jsonrpc_create_reply(result, request->id);
     815                 :            : 
     816                 :            : error:
     817                 :          0 :     reply = jsonrpc_create_error(ovsdb_error_to_json(error), request->id);
     818                 :          0 :     ovsdb_error_destroy(error);
     819                 :        636 :     return reply;
     820                 :            : }
     821                 :            : 
     822                 :            : static void
     823                 :      16245 : ovsdb_jsonrpc_session_unlock_all(struct ovsdb_jsonrpc_session *s)
     824                 :            : {
     825                 :            :     struct ovsdb_lock_waiter *waiter, *next;
     826                 :            : 
     827 [ +  + ][ -  + ]:      16879 :     HMAP_FOR_EACH_SAFE (waiter, next, session_node, &s->up.waiters) {
                 [ +  + ]
     828                 :        634 :         ovsdb_jsonrpc_session_unlock__(waiter);
     829                 :            :     }
     830                 :      16245 : }
     831                 :            : 
     832                 :            : static void
     833                 :        636 : ovsdb_jsonrpc_session_unlock__(struct ovsdb_lock_waiter *waiter)
     834                 :            : {
     835                 :        636 :     struct ovsdb_lock *lock = waiter->lock;
     836                 :            : 
     837         [ +  - ]:        636 :     if (lock) {
     838                 :        636 :         struct ovsdb_session *new_owner = ovsdb_lock_waiter_remove(waiter);
     839         [ +  + ]:        636 :         if (new_owner) {
     840                 :          3 :             ovsdb_jsonrpc_session_notify(new_owner, lock->name, "locked");
     841                 :            :         } else {
     842                 :            :             /* ovsdb_server_lock() might have freed 'lock'. */
     843                 :            :         }
     844                 :            :     }
     845                 :            : 
     846                 :        636 :     ovsdb_lock_waiter_destroy(waiter);
     847                 :        636 : }
     848                 :            : 
     849                 :            : static struct jsonrpc_msg *
     850                 :          2 : ovsdb_jsonrpc_session_unlock(struct ovsdb_jsonrpc_session *s,
     851                 :            :                              struct jsonrpc_msg *request)
     852                 :            : {
     853                 :            :     struct ovsdb_lock_waiter *waiter;
     854                 :            :     struct jsonrpc_msg *reply;
     855                 :            :     struct ovsdb_error *error;
     856                 :            :     const char *lock_name;
     857                 :            : 
     858         [ -  + ]:          2 :     if (s->read_only) {
     859                 :          0 :         return jsonrpc_create_readonly_lock_error(request->id);
     860                 :            :     }
     861                 :            : 
     862                 :          2 :     error = ovsdb_jsonrpc_session_parse_lock_name(request, &lock_name);
     863         [ -  + ]:          2 :     if (error) {
     864                 :          0 :         goto error;
     865                 :            :     }
     866                 :            : 
     867                 :            :     /* Report error if this session has not issued a "lock" or "steal" for this
     868                 :            :      * lock. */
     869                 :          2 :     waiter = ovsdb_session_get_lock_waiter(&s->up, lock_name);
     870         [ -  + ]:          2 :     if (!waiter) {
     871                 :          0 :         error = ovsdb_syntax_error(
     872                 :          0 :             request->params, NULL, "\"unlock\" without \"lock\" or \"steal\"");
     873                 :          0 :         goto error;
     874                 :            :     }
     875                 :            : 
     876                 :          2 :     ovsdb_jsonrpc_session_unlock__(waiter);
     877                 :            : 
     878                 :          2 :     return jsonrpc_create_reply(json_object_create(), request->id);
     879                 :            : 
     880                 :            : error:
     881                 :          0 :     reply = jsonrpc_create_error(ovsdb_error_to_json(error), request->id);
     882                 :          0 :     ovsdb_error_destroy(error);
     883                 :          2 :     return reply;
     884                 :            : }
     885                 :            : 
     886                 :            : static struct jsonrpc_msg *
     887                 :      12215 : execute_transaction(struct ovsdb_jsonrpc_session *s, struct ovsdb *db,
     888                 :            :                     struct jsonrpc_msg *request)
     889                 :            : {
     890                 :      12215 :     ovsdb_jsonrpc_trigger_create(s, db, request->id, request->params);
     891                 :      12215 :     request->id = NULL;
     892                 :      12215 :     request->params = NULL;
     893                 :      12215 :     jsonrpc_msg_destroy(request);
     894                 :      12215 :     return NULL;
     895                 :            : }
     896                 :            : 
     897                 :            : static void
     898                 :      27454 : ovsdb_jsonrpc_session_got_request(struct ovsdb_jsonrpc_session *s,
     899                 :            :                                   struct jsonrpc_msg *request)
     900                 :            : {
     901                 :            :     struct jsonrpc_msg *reply;
     902                 :            : 
     903         [ +  + ]:      27454 :     if (!strcmp(request->method, "transact")) {
     904                 :      12215 :         struct ovsdb *db = ovsdb_jsonrpc_lookup_db(s, request, &reply);
     905         [ +  - ]:      12215 :         if (!reply) {
     906                 :      12215 :             reply = execute_transaction(s, db, request);
     907                 :            :         }
     908 [ +  + ][ +  + ]:      15239 :     } else if (!strcmp(request->method, "monitor") ||
     909         [ +  + ]:      15166 :                (monitor_cond_enable__ && !strcmp(request->method,
     910                 :       7140 :                                                  "monitor_cond"))) {
     911                 :       7140 :         struct ovsdb *db = ovsdb_jsonrpc_lookup_db(s, request, &reply);
     912         [ +  - ]:       7140 :         if (!reply) {
     913                 :       7140 :             int l = strlen(request->method) - strlen("monitor");
     914                 :       7140 :             enum ovsdb_monitor_version version = l ? OVSDB_MONITOR_V2
     915                 :       7140 :                                                    : OVSDB_MONITOR_V1;
     916                 :       7140 :             reply = ovsdb_jsonrpc_monitor_create(s, db, request->params,
     917                 :       7140 :                                                  version, request->id);
     918                 :            :         }
     919         [ +  + ]:       8099 :     } else if (!strcmp(request->method, "monitor_cond_change")) {
     920                 :        149 :         reply = ovsdb_jsonrpc_monitor_cond_change(s, request->params,
     921                 :        149 :                                                   request->id);
     922         [ -  + ]:       7950 :     } else if (!strcmp(request->method, "monitor_cancel")) {
     923                 :          0 :         reply = ovsdb_jsonrpc_monitor_cancel(s, json_array(request->params),
     924                 :          0 :                                              request->id);
     925         [ +  + ]:       7950 :     } else if (!strcmp(request->method, "get_schema")) {
     926                 :       7111 :         struct ovsdb *db = ovsdb_jsonrpc_lookup_db(s, request, &reply);
     927         [ +  + ]:       7111 :         if (!reply) {
     928                 :       7111 :             reply = jsonrpc_create_reply(ovsdb_schema_to_json(db->schema),
     929                 :       7110 :                                          request->id);
     930                 :            :         }
     931         [ +  + ]:        839 :     } else if (!strcmp(request->method, "list_dbs")) {
     932                 :        197 :         size_t n_dbs = shash_count(&s->up.server->dbs);
     933                 :            :         struct shash_node *node;
     934                 :            :         struct json **dbs;
     935                 :            :         size_t i;
     936                 :            : 
     937                 :        197 :         dbs = xmalloc(n_dbs * sizeof *dbs);
     938                 :        197 :         i = 0;
     939 [ +  + ][ -  + ]:        396 :         SHASH_FOR_EACH (node, &s->up.server->dbs) {
     940                 :        199 :             dbs[i++] = json_string_create(node->name);
     941                 :            :         }
     942                 :        197 :         reply = jsonrpc_create_reply(json_array_create(dbs, n_dbs),
     943                 :        197 :                                      request->id);
     944         [ +  + ]:        642 :     } else if (!strcmp(request->method, "lock")) {
     945                 :        635 :         reply = ovsdb_jsonrpc_session_lock(s, request, OVSDB_LOCK_WAIT);
     946         [ +  + ]:          7 :     } else if (!strcmp(request->method, "steal")) {
     947                 :          1 :         reply = ovsdb_jsonrpc_session_lock(s, request, OVSDB_LOCK_STEAL);
     948         [ +  + ]:          6 :     } else if (!strcmp(request->method, "unlock")) {
     949                 :          2 :         reply = ovsdb_jsonrpc_session_unlock(s, request);
     950         [ -  + ]:          4 :     } else if (!strcmp(request->method, "echo")) {
     951                 :          0 :         reply = jsonrpc_create_reply(json_clone(request->params), request->id);
     952                 :            :     } else {
     953                 :          4 :         reply = jsonrpc_create_error(json_string_create("unknown method"),
     954                 :          4 :                                      request->id);
     955                 :            :     }
     956                 :            : 
     957         [ +  + ]:      27454 :     if (reply) {
     958                 :      15239 :         jsonrpc_msg_destroy(request);
     959                 :      15239 :         ovsdb_jsonrpc_session_send(s, reply);
     960                 :            :     }
     961                 :      27454 : }
     962                 :            : 
     963                 :            : static void
     964                 :          0 : execute_cancel(struct ovsdb_jsonrpc_session *s, struct jsonrpc_msg *request)
     965                 :            : {
     966         [ #  # ]:          0 :     if (json_array(request->params)->n == 1) {
     967                 :            :         struct ovsdb_jsonrpc_trigger *t;
     968                 :            :         struct json *id;
     969                 :            : 
     970                 :          0 :         id = request->params->u.array.elems[0];
     971                 :          0 :         t = ovsdb_jsonrpc_trigger_find(s, id, json_hash(id, 0));
     972         [ #  # ]:          0 :         if (t) {
     973                 :          0 :             ovsdb_jsonrpc_trigger_complete(t);
     974                 :            :         }
     975                 :            :     }
     976                 :          0 : }
     977                 :            : 
     978                 :            : static void
     979                 :          0 : ovsdb_jsonrpc_session_got_notify(struct ovsdb_jsonrpc_session *s,
     980                 :            :                                  struct jsonrpc_msg *request)
     981                 :            : {
     982         [ #  # ]:          0 :     if (!strcmp(request->method, "cancel")) {
     983                 :          0 :         execute_cancel(s, request);
     984                 :            :     }
     985                 :          0 :     jsonrpc_msg_destroy(request);
     986                 :          0 : }
     987                 :            : 
     988                 :            : static void
     989                 :      27458 : ovsdb_jsonrpc_session_send(struct ovsdb_jsonrpc_session *s,
     990                 :            :                            struct jsonrpc_msg *msg)
     991                 :            : {
     992                 :      27458 :     ovsdb_jsonrpc_monitor_flush_all(s);
     993                 :      27458 :     jsonrpc_session_send(s->js, msg);
     994                 :      27458 : }
     995                 :            : 
     996                 :            : /* JSON-RPC database server triggers.
     997                 :            :  *
     998                 :            :  * (Every transaction is treated as a trigger even if it doesn't actually have
     999                 :            :  * any "wait" operations.) */
    1000                 :            : 
    1001                 :            : struct ovsdb_jsonrpc_trigger {
    1002                 :            :     struct ovsdb_trigger trigger;
    1003                 :            :     struct hmap_node hmap_node; /* In session's "triggers" hmap. */
    1004                 :            :     struct json *id;
    1005                 :            : };
    1006                 :            : 
    1007                 :            : static void
    1008                 :      12215 : ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session *s, struct ovsdb *db,
    1009                 :            :                              struct json *id, struct json *params)
    1010                 :            : {
    1011                 :            :     struct ovsdb_jsonrpc_trigger *t;
    1012                 :            :     size_t hash;
    1013                 :            : 
    1014                 :            :     /* Check for duplicate ID. */
    1015                 :      12215 :     hash = json_hash(id, 0);
    1016                 :      12215 :     t = ovsdb_jsonrpc_trigger_find(s, id, hash);
    1017         [ -  + ]:      12215 :     if (t) {
    1018                 :            :         struct jsonrpc_msg *msg;
    1019                 :            : 
    1020                 :          0 :         msg = jsonrpc_create_error(json_string_create("duplicate request ID"),
    1021                 :            :                                    id);
    1022                 :          0 :         ovsdb_jsonrpc_session_send(s, msg);
    1023                 :          0 :         json_destroy(id);
    1024                 :          0 :         json_destroy(params);
    1025                 :          0 :         return;
    1026                 :            :     }
    1027                 :            : 
    1028                 :            :     /* Insert into trigger table. */
    1029                 :      12215 :     t = xmalloc(sizeof *t);
    1030                 :      12215 :     ovsdb_trigger_init(&s->up, db, &t->trigger, params, time_msec(),
    1031                 :      12215 :                        s->read_only);
    1032                 :      12215 :     t->id = id;
    1033                 :      12215 :     hmap_insert(&s->triggers, &t->hmap_node, hash);
    1034                 :            : 
    1035                 :            :     /* Complete early if possible. */
    1036         [ +  - ]:      12215 :     if (ovsdb_trigger_is_complete(&t->trigger)) {
    1037                 :      12215 :         ovsdb_jsonrpc_trigger_complete(t);
    1038                 :            :     }
    1039                 :            : }
    1040                 :            : 
    1041                 :            : static struct ovsdb_jsonrpc_trigger *
    1042                 :      12215 : ovsdb_jsonrpc_trigger_find(struct ovsdb_jsonrpc_session *s,
    1043                 :            :                            const struct json *id, size_t hash)
    1044                 :            : {
    1045                 :            :     struct ovsdb_jsonrpc_trigger *t;
    1046                 :            : 
    1047 [ -  + ][ -  + ]:      12215 :     HMAP_FOR_EACH_WITH_HASH (t, hmap_node, hash, &s->triggers) {
    1048         [ #  # ]:          0 :         if (json_equal(t->id, id)) {
    1049                 :          0 :             return t;
    1050                 :            :         }
    1051                 :            :     }
    1052                 :            : 
    1053                 :      12215 :     return NULL;
    1054                 :            : }
    1055                 :            : 
    1056                 :            : static void
    1057                 :      12215 : ovsdb_jsonrpc_trigger_complete(struct ovsdb_jsonrpc_trigger *t)
    1058                 :            : {
    1059                 :            :     struct ovsdb_jsonrpc_session *s;
    1060                 :            : 
    1061                 :      12215 :     s = CONTAINER_OF(t->trigger.session, struct ovsdb_jsonrpc_session, up);
    1062                 :            : 
    1063         [ +  - ]:      12215 :     if (jsonrpc_session_is_connected(s->js)) {
    1064                 :            :         struct jsonrpc_msg *reply;
    1065                 :            :         struct json *result;
    1066                 :            : 
    1067                 :      12215 :         result = ovsdb_trigger_steal_result(&t->trigger);
    1068         [ +  - ]:      12215 :         if (result) {
    1069                 :      12215 :             reply = jsonrpc_create_reply(result, t->id);
    1070                 :            :         } else {
    1071                 :          0 :             reply = jsonrpc_create_error(json_string_create("canceled"),
    1072                 :          0 :                                          t->id);
    1073                 :            :         }
    1074                 :      12215 :         ovsdb_jsonrpc_session_send(s, reply);
    1075                 :            :     }
    1076                 :            : 
    1077                 :      12215 :     json_destroy(t->id);
    1078                 :      12215 :     ovsdb_trigger_destroy(&t->trigger);
    1079                 :      12215 :     hmap_remove(&s->triggers, &t->hmap_node);
    1080                 :      12215 :     free(t);
    1081                 :      12215 : }
    1082                 :            : 
    1083                 :            : static void
    1084                 :      16245 : ovsdb_jsonrpc_trigger_complete_all(struct ovsdb_jsonrpc_session *s)
    1085                 :            : {
    1086                 :            :     struct ovsdb_jsonrpc_trigger *t, *next;
    1087 [ +  - ][ -  + ]:      16245 :     HMAP_FOR_EACH_SAFE (t, next, hmap_node, &s->triggers) {
                 [ -  + ]
    1088                 :          0 :         ovsdb_jsonrpc_trigger_complete(t);
    1089                 :            :     }
    1090                 :      16245 : }
    1091                 :            : 
    1092                 :            : static void
    1093                 :      95115 : ovsdb_jsonrpc_trigger_complete_done(struct ovsdb_jsonrpc_session *s)
    1094                 :            : {
    1095         [ -  + ]:      95115 :     while (!ovs_list_is_empty(&s->up.completions)) {
    1096                 :          0 :         struct ovsdb_jsonrpc_trigger *t
    1097                 :          0 :             = CONTAINER_OF(s->up.completions.next,
    1098                 :            :                            struct ovsdb_jsonrpc_trigger, trigger.node);
    1099                 :          0 :         ovsdb_jsonrpc_trigger_complete(t);
    1100                 :            :     }
    1101                 :      95115 : }
    1102                 :            : 
    1103                 :            : /* Jsonrpc front end monitor. */
    1104                 :            : struct ovsdb_jsonrpc_monitor {
    1105                 :            :     struct hmap_node node;      /* In ovsdb_jsonrpc_session's "monitors". */
    1106                 :            :     struct ovsdb_jsonrpc_session *session;
    1107                 :            :     struct ovsdb *db;
    1108                 :            :     struct json *monitor_id;
    1109                 :            :     struct ovsdb_monitor *dbmon;
    1110                 :            :     uint64_t unflushed;         /* The first transaction that has not been
    1111                 :            :                                        flushed to the jsonrpc remote client. */
    1112                 :            :     enum ovsdb_monitor_version version;
    1113                 :            :     struct ovsdb_monitor_session_condition *condition;/* Session's condition */
    1114                 :            : };
    1115                 :            : 
    1116                 :            : static struct ovsdb_jsonrpc_monitor *
    1117                 :       7289 : ovsdb_jsonrpc_monitor_find(struct ovsdb_jsonrpc_session *s,
    1118                 :            :                            const struct json *monitor_id)
    1119                 :            : {
    1120                 :            :     struct ovsdb_jsonrpc_monitor *m;
    1121                 :            : 
    1122 [ +  + ][ -  + ]:       7289 :     HMAP_FOR_EACH_WITH_HASH (m, node, json_hash(monitor_id, 0), &s->monitors) {
    1123         [ +  - ]:        149 :         if (json_equal(m->monitor_id, monitor_id)) {
    1124                 :        149 :             return m;
    1125                 :            :         }
    1126                 :            :     }
    1127                 :            : 
    1128                 :       7140 :     return NULL;
    1129                 :            : }
    1130                 :            : 
    1131                 :            : static bool
    1132                 :         24 : parse_bool(struct ovsdb_parser *parser, const char *name, bool default_value)
    1133                 :            : {
    1134                 :            :     const struct json *json;
    1135                 :            : 
    1136                 :         24 :     json = ovsdb_parser_member(parser, name, OP_BOOLEAN | OP_OPTIONAL);
    1137         [ +  - ]:         24 :     return json ? json_boolean(json) : default_value;
    1138                 :            : }
    1139                 :            : 
    1140                 :            : static struct ovsdb_error * OVS_WARN_UNUSED_RESULT
    1141                 :      44211 : ovsdb_jsonrpc_parse_monitor_request(
    1142                 :            :                                struct ovsdb_monitor *dbmon,
    1143                 :            :                                const struct ovsdb_table *table,
    1144                 :            :                                struct ovsdb_monitor_session_condition *cond,
    1145                 :            :                                const struct json *monitor_request)
    1146                 :            : {
    1147                 :      44211 :     const struct ovsdb_table_schema *ts = table->schema;
    1148                 :            :     enum ovsdb_monitor_selection select;
    1149                 :      44211 :     const struct json *columns, *select_json, *where = NULL;
    1150                 :            :     struct ovsdb_parser parser;
    1151                 :            :     struct ovsdb_error *error;
    1152                 :            : 
    1153                 :      44211 :     ovsdb_parser_init(&parser, monitor_request, "table %s", ts->name);
    1154         [ +  + ]:      44211 :     if (cond) {
    1155                 :      44032 :         where = ovsdb_parser_member(&parser, "where", OP_ARRAY | OP_OPTIONAL);
    1156                 :            :     }
    1157                 :      44211 :     columns = ovsdb_parser_member(&parser, "columns", OP_ARRAY | OP_OPTIONAL);
    1158                 :            : 
    1159                 :      44211 :     select_json = ovsdb_parser_member(&parser, "select",
    1160                 :            :                                       OP_OBJECT | OP_OPTIONAL);
    1161                 :            : 
    1162                 :      44211 :     error = ovsdb_parser_finish(&parser);
    1163         [ -  + ]:      44211 :     if (error) {
    1164                 :          0 :         return error;
    1165                 :            :     }
    1166                 :            : 
    1167         [ +  + ]:      44211 :     if (select_json) {
    1168                 :          6 :         select = 0;
    1169                 :          6 :         ovsdb_parser_init(&parser, select_json, "table %s select", ts->name);
    1170         [ +  + ]:          6 :         if (parse_bool(&parser, "initial", true)) {
    1171                 :          1 :             select |= OJMS_INITIAL;
    1172                 :            :         }
    1173         [ +  + ]:          6 :         if (parse_bool(&parser, "insert", true)) {
    1174                 :          2 :             select |= OJMS_INSERT;
    1175                 :            :         }
    1176         [ +  + ]:          6 :         if (parse_bool(&parser, "delete", true)) {
    1177                 :          2 :             select |= OJMS_DELETE;
    1178                 :            :         }
    1179         [ +  + ]:          6 :         if (parse_bool(&parser, "modify", true)) {
    1180                 :          1 :             select |= OJMS_MODIFY;
    1181                 :            :         }
    1182                 :          6 :         error = ovsdb_parser_finish(&parser);
    1183         [ -  + ]:          6 :         if (error) {
    1184                 :          0 :             return error;
    1185                 :            :         }
    1186                 :            :     } else {
    1187                 :      44205 :         select = OJMS_INITIAL | OJMS_INSERT | OJMS_DELETE | OJMS_MODIFY;
    1188                 :            :     }
    1189                 :            : 
    1190                 :      44211 :     ovsdb_monitor_table_add_select(dbmon, table, select);
    1191         [ +  + ]:      44211 :     if (columns) {
    1192                 :            :         size_t i;
    1193                 :            : 
    1194         [ -  + ]:      44164 :         if (columns->type != JSON_ARRAY) {
    1195                 :          0 :             return ovsdb_syntax_error(columns, NULL,
    1196                 :            :                                       "array of column names expected");
    1197                 :            :         }
    1198                 :            : 
    1199         [ +  + ]:     245575 :         for (i = 0; i < columns->u.array.n; i++) {
    1200                 :            :             const struct ovsdb_column *column;
    1201                 :            :             const char *s;
    1202                 :            : 
    1203         [ -  + ]:     201411 :             if (columns->u.array.elems[i]->type != JSON_STRING) {
    1204                 :          0 :                 return ovsdb_syntax_error(columns, NULL,
    1205                 :            :                                           "array of column names expected");
    1206                 :            :             }
    1207                 :            : 
    1208                 :     201411 :             s = columns->u.array.elems[i]->u.string;
    1209                 :     201411 :             column = shash_find_data(&table->schema->columns, s);
    1210         [ -  + ]:     201411 :             if (!column) {
    1211                 :          0 :                 return ovsdb_syntax_error(columns, NULL, "%s is not a valid "
    1212                 :            :                                           "column name", s);
    1213                 :            :             }
    1214         [ -  + ]:     201411 :             if (ovsdb_monitor_add_column(dbmon, table, column,
    1215                 :            :                                          select, true)) {
    1216                 :          0 :                 return ovsdb_syntax_error(columns, NULL, "column %s "
    1217                 :            :                                           "mentioned more than once",
    1218                 :            :                                           column->name);
    1219                 :            :             }
    1220                 :            :         }
    1221                 :            :     } else {
    1222                 :            :         struct shash_node *node;
    1223                 :            : 
    1224 [ +  + ][ -  + ]:        245 :         SHASH_FOR_EACH (node, &ts->columns) {
    1225                 :        198 :             const struct ovsdb_column *column = node->data;
    1226         [ +  + ]:        198 :             if (column->index != OVSDB_COL_UUID) {
    1227         [ -  + ]:        151 :                 if (ovsdb_monitor_add_column(dbmon, table, column,
    1228                 :            :                                              select, true)) {
    1229                 :          0 :                     return ovsdb_syntax_error(columns, NULL, "column %s "
    1230                 :            :                                               "mentioned more than once",
    1231                 :            :                                               column->name);
    1232                 :            :                 }
    1233                 :            :             }
    1234                 :            :         }
    1235                 :            :     }
    1236         [ +  + ]:      44211 :     if (cond) {
    1237                 :      44032 :         error = ovsdb_monitor_table_condition_create(cond, table, where);
    1238         [ -  + ]:      44032 :         if (error) {
    1239                 :          0 :             return error;
    1240                 :            :         }
    1241                 :            :     }
    1242                 :            : 
    1243                 :      44211 :     return NULL;
    1244                 :            : }
    1245                 :            : 
    1246                 :            : static struct jsonrpc_msg *
    1247                 :       7140 : ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s, struct ovsdb *db,
    1248                 :            :                              struct json *params,
    1249                 :            :                              enum ovsdb_monitor_version version,
    1250                 :            :                              const struct json *request_id)
    1251                 :            : {
    1252                 :       7140 :     struct ovsdb_jsonrpc_monitor *m = NULL;
    1253                 :       7140 :     struct ovsdb_monitor *dbmon = NULL;
    1254                 :            :     struct json *monitor_id, *monitor_requests;
    1255                 :       7140 :     struct ovsdb_error *error = NULL;
    1256                 :            :     struct shash_node *node;
    1257                 :            :     struct json *json;
    1258                 :            : 
    1259         [ -  + ]:       7140 :     if (json_array(params)->n != 3) {
    1260                 :          0 :         error = ovsdb_syntax_error(params, NULL, "invalid parameters");
    1261                 :          0 :         goto error;
    1262                 :            :     }
    1263                 :       7140 :     monitor_id = params->u.array.elems[1];
    1264                 :       7140 :     monitor_requests = params->u.array.elems[2];
    1265         [ -  + ]:       7140 :     if (monitor_requests->type != JSON_OBJECT) {
    1266                 :          0 :         error = ovsdb_syntax_error(monitor_requests, NULL,
    1267                 :            :                                    "monitor-requests must be object");
    1268                 :          0 :         goto error;
    1269                 :            :     }
    1270                 :            : 
    1271         [ -  + ]:       7140 :     if (ovsdb_jsonrpc_monitor_find(s, monitor_id)) {
    1272                 :          0 :         error = ovsdb_syntax_error(monitor_id, NULL, "duplicate monitor ID");
    1273                 :          0 :         goto error;
    1274                 :            :     }
    1275                 :            : 
    1276                 :       7140 :     m = xzalloc(sizeof *m);
    1277                 :       7140 :     m->session = s;
    1278                 :       7140 :     m->db = db;
    1279                 :       7140 :     m->dbmon = ovsdb_monitor_create(db, m);
    1280         [ +  + ]:       7140 :     if (version == OVSDB_MONITOR_V2) {
    1281                 :       7075 :         m->condition = ovsdb_monitor_session_condition_create();
    1282                 :            :     }
    1283                 :       7140 :     m->unflushed = 0;
    1284                 :       7140 :     m->version = version;
    1285                 :       7140 :     hmap_insert(&s->monitors, &m->node, json_hash(monitor_id, 0));
    1286                 :       7140 :     m->monitor_id = json_clone(monitor_id);
    1287                 :            : 
    1288 [ +  + ][ -  + ]:      51351 :     SHASH_FOR_EACH (node, json_object(monitor_requests)) {
    1289                 :            :         const struct ovsdb_table *table;
    1290                 :            :         const struct json *mr_value;
    1291                 :            :         size_t i;
    1292                 :            : 
    1293                 :      44211 :         table = ovsdb_get_table(m->db, node->name);
    1294         [ -  + ]:      44211 :         if (!table) {
    1295                 :          0 :             error = ovsdb_syntax_error(NULL, NULL,
    1296                 :            :                                        "no table named %s", node->name);
    1297                 :          0 :             goto error;
    1298                 :            :         }
    1299                 :            : 
    1300                 :      44211 :         ovsdb_monitor_add_table(m->dbmon, table);
    1301                 :            : 
    1302                 :            :         /* Parse columns. */
    1303                 :      44211 :         mr_value = node->data;
    1304         [ +  + ]:      44211 :         if (mr_value->type == JSON_ARRAY) {
    1305                 :        100 :             const struct json_array *array = &mr_value->u.array;
    1306                 :            : 
    1307         [ +  + ]:        200 :             for (i = 0; i < array->n; i++) {
    1308                 :        100 :                 error = ovsdb_jsonrpc_parse_monitor_request(m->dbmon,
    1309                 :            :                                                             table,
    1310                 :            :                                                             m->condition,
    1311                 :        100 :                                                             array->elems[i]);
    1312         [ -  + ]:        100 :                 if (error) {
    1313                 :          0 :                     goto error;
    1314                 :            :                 }
    1315                 :            :             }
    1316                 :            :         } else {
    1317                 :      44111 :             error = ovsdb_jsonrpc_parse_monitor_request(m->dbmon,
    1318                 :            :                                                         table,
    1319                 :            :                                                         m->condition,
    1320                 :            :                                                         mr_value);
    1321         [ -  + ]:      44111 :             if (error) {
    1322                 :          0 :                 goto error;
    1323                 :            :             }
    1324                 :            :         }
    1325                 :            :     }
    1326                 :            : 
    1327                 :       7140 :     dbmon = ovsdb_monitor_add(m->dbmon);
    1328         [ +  + ]:       7140 :     if (dbmon != m->dbmon) {
    1329                 :            :         /* Found an exisiting dbmon, reuse the current one. */
    1330                 :        602 :         ovsdb_monitor_remove_jsonrpc_monitor(m->dbmon, m, m->unflushed);
    1331                 :        602 :         ovsdb_monitor_add_jsonrpc_monitor(dbmon, m);
    1332                 :        602 :         m->dbmon = dbmon;
    1333                 :            :     }
    1334                 :            : 
    1335                 :            :     /* Only now we can bind session's condition to ovsdb_monitor */
    1336         [ +  + ]:       7140 :     if (m->condition) {
    1337                 :       7075 :         ovsdb_monitor_condition_bind(m->dbmon, m->condition);
    1338                 :            :     }
    1339                 :            : 
    1340                 :       7140 :     ovsdb_monitor_get_initial(m->dbmon);
    1341                 :       7140 :     json = ovsdb_jsonrpc_monitor_compose_update(m, true);
    1342         [ +  + ]:       7140 :     json = json ? json : json_object_create();
    1343                 :       7140 :     return jsonrpc_create_reply(json, request_id);
    1344                 :            : 
    1345                 :            : error:
    1346         [ #  # ]:          0 :     if (m) {
    1347                 :          0 :         ovsdb_jsonrpc_monitor_destroy(m);
    1348                 :            :     }
    1349                 :            : 
    1350                 :          0 :     json = ovsdb_error_to_json(error);
    1351                 :          0 :     ovsdb_error_destroy(error);
    1352                 :          0 :     return jsonrpc_create_error(json, request_id);
    1353                 :            : }
    1354                 :            : 
    1355                 :            : static struct ovsdb_error *
    1356                 :        149 : ovsdb_jsonrpc_parse_monitor_cond_change_request(
    1357                 :            :                                 struct ovsdb_jsonrpc_monitor *m,
    1358                 :            :                                 const struct ovsdb_table *table,
    1359                 :            :                                 const struct json *cond_change_req)
    1360                 :            : {
    1361                 :        149 :     const struct ovsdb_table_schema *ts = table->schema;
    1362                 :            :     const struct json *condition, *columns;
    1363                 :            :     struct ovsdb_parser parser;
    1364                 :            :     struct ovsdb_error *error;
    1365                 :            : 
    1366                 :        149 :     ovsdb_parser_init(&parser, cond_change_req, "table %s", ts->name);
    1367                 :        149 :     columns = ovsdb_parser_member(&parser, "columns", OP_ARRAY | OP_OPTIONAL);
    1368                 :        149 :     condition = ovsdb_parser_member(&parser, "where", OP_ARRAY | OP_OPTIONAL);
    1369                 :            : 
    1370                 :        149 :     error = ovsdb_parser_finish(&parser);
    1371         [ -  + ]:        149 :     if (error) {
    1372                 :          0 :         return error;
    1373                 :            :     }
    1374                 :            : 
    1375         [ -  + ]:        149 :     if (columns) {
    1376                 :          0 :         error = ovsdb_syntax_error(cond_change_req, NULL, "changing columns "
    1377                 :            :                                    "is unsupported");
    1378                 :          0 :         return error;
    1379                 :            :     }
    1380                 :        149 :     error = ovsdb_monitor_table_condition_update(m->dbmon, m->condition, table,
    1381                 :            :                                                  condition);
    1382                 :            : 
    1383                 :        149 :     return error;
    1384                 :            : }
    1385                 :            : 
    1386                 :            : static struct jsonrpc_msg *
    1387                 :        149 : ovsdb_jsonrpc_monitor_cond_change(struct ovsdb_jsonrpc_session *s,
    1388                 :            :                                   struct json *params,
    1389                 :            :                                   const struct json *request_id)
    1390                 :            : {
    1391                 :            :     struct ovsdb_error *error;
    1392                 :            :     struct ovsdb_jsonrpc_monitor *m;
    1393                 :            :     struct json *monitor_cond_change_reqs;
    1394                 :            :     struct shash_node *node;
    1395                 :            :     struct json *json;
    1396                 :            : 
    1397         [ -  + ]:        149 :     if (json_array(params)->n != 3) {
    1398                 :          0 :         error = ovsdb_syntax_error(params, NULL, "invalid parameters");
    1399                 :          0 :         goto error;
    1400                 :            :     }
    1401                 :            : 
    1402                 :        149 :     m = ovsdb_jsonrpc_monitor_find(s, params->u.array.elems[0]);
    1403         [ -  + ]:        149 :     if (!m) {
    1404                 :          0 :         error = ovsdb_syntax_error(request_id, NULL,
    1405                 :            :                                    "unknown monitor session");
    1406                 :          0 :         goto error;
    1407                 :            :     }
    1408                 :            : 
    1409                 :        149 :     monitor_cond_change_reqs = params->u.array.elems[2];
    1410         [ -  + ]:        149 :     if (monitor_cond_change_reqs->type != JSON_OBJECT) {
    1411                 :          0 :         error =
    1412                 :            :             ovsdb_syntax_error(NULL, NULL,
    1413                 :            :                                "monitor-cond-change-requests must be object");
    1414                 :          0 :         goto error;
    1415                 :            :     }
    1416                 :            : 
    1417 [ +  + ][ -  + ]:        298 :     SHASH_FOR_EACH (node, json_object(monitor_cond_change_reqs)) {
    1418                 :            :         const struct ovsdb_table *table;
    1419                 :            :         const struct json *mr_value;
    1420                 :            :         size_t i;
    1421                 :            : 
    1422                 :        149 :         table = ovsdb_get_table(m->db, node->name);
    1423         [ -  + ]:        149 :         if (!table) {
    1424                 :          0 :             error = ovsdb_syntax_error(NULL, NULL,
    1425                 :            :                                        "no table named %s", node->name);
    1426                 :          0 :             goto error;
    1427                 :            :         }
    1428         [ -  + ]:        149 :         if (!ovsdb_monitor_table_exists(m->dbmon, table)) {
    1429                 :          0 :             error = ovsdb_syntax_error(NULL, NULL,
    1430                 :            :                                        "no table named %s in monitor session",
    1431                 :            :                                        node->name);
    1432                 :          0 :             goto error;
    1433                 :            :         }
    1434                 :            : 
    1435                 :        149 :         mr_value = node->data;
    1436         [ +  - ]:        149 :         if (mr_value->type == JSON_ARRAY) {
    1437                 :        149 :             const struct json_array *array = &mr_value->u.array;
    1438                 :            : 
    1439         [ +  + ]:        298 :             for (i = 0; i < array->n; i++) {
    1440                 :        149 :                 error = ovsdb_jsonrpc_parse_monitor_cond_change_request(
    1441                 :        149 :                                             m, table, array->elems[i]);
    1442         [ -  + ]:        149 :                 if (error) {
    1443                 :          0 :                     goto error;
    1444                 :            :                 }
    1445                 :            :             }
    1446                 :            :         } else {
    1447                 :          0 :             error = ovsdb_syntax_error(
    1448                 :            :                        NULL, NULL,
    1449                 :            :                        "table %s no monitor-cond-change JSON array",
    1450                 :            :                        node->name);
    1451                 :          0 :             goto error;
    1452                 :            :         }
    1453                 :            :     }
    1454                 :            : 
    1455                 :            :     /* Change monitor id */
    1456                 :        149 :     hmap_remove(&s->monitors, &m->node);
    1457                 :        149 :     json_destroy(m->monitor_id);
    1458                 :        149 :     m->monitor_id = json_clone(params->u.array.elems[1]);
    1459                 :        149 :     hmap_insert(&s->monitors, &m->node, json_hash(m->monitor_id, 0));
    1460                 :            : 
    1461                 :            :     /* Send the new update, if any,  represents the difference from the old
    1462                 :            :      * condition and the new one. */
    1463                 :            :     struct json *update_json;
    1464                 :            : 
    1465                 :        149 :     update_json = ovsdb_monitor_get_update(m->dbmon, false, true,
    1466                 :            :                                     &m->unflushed, m->condition, m->version);
    1467         [ +  + ]:        149 :     if (update_json) {
    1468                 :            :         struct jsonrpc_msg *msg;
    1469                 :            :         struct json *params;
    1470                 :            : 
    1471                 :         85 :         params = json_array_create_2(json_clone(m->monitor_id), update_json);
    1472                 :         85 :         msg = ovsdb_jsonrpc_create_notify(m, params);
    1473                 :         85 :         jsonrpc_session_send(s->js, msg);
    1474                 :            :     }
    1475                 :            : 
    1476                 :        149 :     return jsonrpc_create_reply(json_object_create(), request_id);
    1477                 :            : 
    1478                 :            : error:
    1479                 :            : 
    1480                 :          0 :     json = ovsdb_error_to_json(error);
    1481                 :          0 :     ovsdb_error_destroy(error);
    1482                 :          0 :     return jsonrpc_create_error(json, request_id);
    1483                 :            : }
    1484                 :            : 
    1485                 :            : static struct jsonrpc_msg *
    1486                 :          0 : ovsdb_jsonrpc_monitor_cancel(struct ovsdb_jsonrpc_session *s,
    1487                 :            :                              struct json_array *params,
    1488                 :            :                              const struct json *request_id)
    1489                 :            : {
    1490         [ #  # ]:          0 :     if (params->n != 1) {
    1491                 :          0 :         return jsonrpc_create_error(json_string_create("invalid parameters"),
    1492                 :            :                                     request_id);
    1493                 :            :     } else {
    1494                 :            :         struct ovsdb_jsonrpc_monitor *m;
    1495                 :            : 
    1496                 :          0 :         m = ovsdb_jsonrpc_monitor_find(s, params->elems[0]);
    1497         [ #  # ]:          0 :         if (!m) {
    1498                 :          0 :             return jsonrpc_create_error(json_string_create("unknown monitor"),
    1499                 :            :                                         request_id);
    1500                 :            :         } else {
    1501                 :          0 :             ovsdb_jsonrpc_monitor_destroy(m);
    1502                 :          0 :             return jsonrpc_create_reply(json_object_create(), request_id);
    1503                 :            :         }
    1504                 :            :     }
    1505                 :            : }
    1506                 :            : 
    1507                 :            : static void
    1508                 :      16245 : ovsdb_jsonrpc_monitor_remove_all(struct ovsdb_jsonrpc_session *s)
    1509                 :            : {
    1510                 :            :     struct ovsdb_jsonrpc_monitor *m, *next;
    1511                 :            : 
    1512 [ +  + ][ -  + ]:      23385 :     HMAP_FOR_EACH_SAFE (m, next, node, &s->monitors) {
                 [ +  + ]
    1513                 :       7140 :         ovsdb_jsonrpc_monitor_destroy(m);
    1514                 :            :     }
    1515                 :      16245 : }
    1516                 :            : 
    1517                 :            : static struct json *
    1518                 :      88431 : ovsdb_jsonrpc_monitor_compose_update(struct ovsdb_jsonrpc_monitor *m,
    1519                 :            :                                      bool initial)
    1520                 :            : {
    1521                 :            : 
    1522         [ +  + ]:      88431 :     if (!ovsdb_monitor_needs_flush(m->dbmon, m->unflushed)) {
    1523                 :      63847 :         return NULL;
    1524                 :            :     }
    1525                 :            : 
    1526                 :      24584 :     return ovsdb_monitor_get_update(m->dbmon, initial, false,
    1527                 :            :                                     &m->unflushed, m->condition, m->version);
    1528                 :            : }
    1529                 :            : 
    1530                 :            : static bool
    1531                 :      86817 : ovsdb_jsonrpc_monitor_needs_flush(struct ovsdb_jsonrpc_session *s)
    1532                 :            : {
    1533                 :            :     struct ovsdb_jsonrpc_monitor *m;
    1534                 :            : 
    1535 [ +  + ][ -  + ]:     152967 :     HMAP_FOR_EACH (m, node, &s->monitors) {
    1536         [ +  + ]:      69990 :         if (ovsdb_monitor_needs_flush(m->dbmon, m->unflushed)) {
    1537                 :       3840 :             return true;
    1538                 :            :         }
    1539                 :            :     }
    1540                 :            : 
    1541                 :      82977 :     return false;
    1542                 :            : }
    1543                 :            : 
    1544                 :            : void
    1545                 :       7140 : ovsdb_jsonrpc_monitor_destroy(struct ovsdb_jsonrpc_monitor *m)
    1546                 :            : {
    1547                 :       7140 :     json_destroy(m->monitor_id);
    1548                 :       7140 :     hmap_remove(&m->session->monitors, &m->node);
    1549                 :       7140 :     ovsdb_monitor_remove_jsonrpc_monitor(m->dbmon, m, m->unflushed);
    1550                 :       7140 :     ovsdb_monitor_session_condition_destroy(m->condition);
    1551                 :       7140 :     free(m);
    1552                 :       7140 : }
    1553                 :            : 
    1554                 :            : static struct jsonrpc_msg *
    1555                 :      17511 : ovsdb_jsonrpc_create_notify(const struct ovsdb_jsonrpc_monitor *m,
    1556                 :            :                             struct json *params)
    1557                 :            : {
    1558                 :            :     const char *method;
    1559                 :            : 
    1560      [ +  +  - ]:      17511 :     switch(m->version) {
    1561                 :            :     case OVSDB_MONITOR_V1:
    1562                 :        133 :         method = "update";
    1563                 :        133 :         break;
    1564                 :            :     case OVSDB_MONITOR_V2:
    1565                 :      17378 :         method = "update2";
    1566                 :      17378 :         break;
    1567                 :            :     case OVSDB_MONITOR_VERSION_MAX:
    1568                 :            :     default:
    1569                 :          0 :         OVS_NOT_REACHED();
    1570                 :            :     }
    1571                 :            : 
    1572                 :      17511 :     return jsonrpc_create_notify(method, params);
    1573                 :            : }
    1574                 :            : 
    1575                 :            : static void
    1576                 :     122331 : ovsdb_jsonrpc_monitor_flush_all(struct ovsdb_jsonrpc_session *s)
    1577                 :            : {
    1578                 :            :     struct ovsdb_jsonrpc_monitor *m;
    1579                 :            : 
    1580 [ +  + ][ -  + ]:     203622 :     HMAP_FOR_EACH (m, node, &s->monitors) {
    1581                 :            :         struct json *json;
    1582                 :            : 
    1583                 :      81291 :         json = ovsdb_jsonrpc_monitor_compose_update(m, false);
    1584         [ +  + ]:      81291 :         if (json) {
    1585                 :            :             struct jsonrpc_msg *msg;
    1586                 :            :             struct json *params;
    1587                 :            : 
    1588                 :      17426 :             params = json_array_create_2(json_clone(m->monitor_id), json);
    1589                 :      17426 :             msg = ovsdb_jsonrpc_create_notify(m, params);
    1590                 :      17426 :             jsonrpc_session_send(s->js, msg);
    1591                 :            :         }
    1592                 :            :     }
    1593                 :     122331 : }
    1594                 :            : 
    1595                 :            : void
    1596                 :          2 : ovsdb_jsonrpc_disable_monitor_cond(void)
    1597                 :            : {
    1598                 :            :     /* Once disabled, it is not possible to re-enable it. */
    1599                 :          2 :     monitor_cond_enable__ = false;
    1600                 :          2 : }

Generated by: LCOV version 1.12