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 : }
|