+static void
+ovsdb_jsonrpc_add_monitor_column(struct ovsdb_jsonrpc_monitor_table *mt,
+ const struct ovsdb_column *column,
+ enum ovsdb_jsonrpc_monitor_selection select,
+ size_t *allocated_columns)
+{
+ struct ovsdb_jsonrpc_monitor_column *c;
+
+ if (mt->n_columns >= *allocated_columns) {
+ mt->columns = x2nrealloc(mt->columns, allocated_columns,
+ sizeof *mt->columns);
+ }
+
+ c = &mt->columns[mt->n_columns++];
+ c->column = column;
+ c->select = select;
+}
+
+static int
+compare_ovsdb_jsonrpc_monitor_column(const void *a_, const void *b_)
+{
+ const struct ovsdb_jsonrpc_monitor_column *a = a_;
+ const struct ovsdb_jsonrpc_monitor_column *b = b_;
+
+ return a->column < b->column ? -1 : a->column > b->column;
+}
+
+static struct ovsdb_error * WARN_UNUSED_RESULT
+ovsdb_jsonrpc_parse_monitor_request(struct ovsdb_jsonrpc_monitor_table *mt,
+ const struct json *monitor_request,
+ size_t *allocated_columns)
+{
+ const struct ovsdb_table_schema *ts = mt->table->schema;
+ enum ovsdb_jsonrpc_monitor_selection select;
+ const struct json *columns, *select_json;
+ struct ovsdb_parser parser;
+ struct ovsdb_error *error;
+
+ ovsdb_parser_init(&parser, monitor_request, "table %s", ts->name);
+ columns = ovsdb_parser_member(&parser, "columns", OP_ARRAY | OP_OPTIONAL);
+ select_json = ovsdb_parser_member(&parser, "select",
+ OP_OBJECT | OP_OPTIONAL);
+ error = ovsdb_parser_finish(&parser);
+ if (error) {
+ return error;
+ }
+
+ if (select_json) {
+ select = 0;
+ ovsdb_parser_init(&parser, select_json, "table %s select", ts->name);
+ if (parse_bool(&parser, "initial", true)) {
+ select |= OJMS_INITIAL;
+ }
+ if (parse_bool(&parser, "insert", true)) {
+ select |= OJMS_INSERT;
+ }
+ if (parse_bool(&parser, "delete", true)) {
+ select |= OJMS_DELETE;
+ }
+ if (parse_bool(&parser, "modify", true)) {
+ select |= OJMS_MODIFY;
+ }
+ error = ovsdb_parser_finish(&parser);
+ if (error) {
+ return error;
+ }
+ } else {
+ select = OJMS_INITIAL | OJMS_INSERT | OJMS_DELETE | OJMS_MODIFY;
+ }
+ mt->select |= select;
+
+ if (columns) {
+ size_t i;
+
+ if (columns->type != JSON_ARRAY) {
+ return ovsdb_syntax_error(columns, NULL,
+ "array of column names expected");
+ }
+
+ for (i = 0; i < columns->u.array.n; i++) {
+ const struct ovsdb_column *column;
+ const char *s;
+
+ if (columns->u.array.elems[i]->type != JSON_STRING) {
+ return ovsdb_syntax_error(columns, NULL,
+ "array of column names expected");
+ }
+
+ s = columns->u.array.elems[i]->u.string;
+ column = shash_find_data(&mt->table->schema->columns, s);
+ if (!column) {
+ return ovsdb_syntax_error(columns, NULL, "%s is not a valid "
+ "column name", s);
+ }
+ ovsdb_jsonrpc_add_monitor_column(mt, column, select,
+ allocated_columns);
+ }
+ } else {
+ struct shash_node *node;
+
+ SHASH_FOR_EACH (node, &ts->columns) {
+ const struct ovsdb_column *column = node->data;
+ if (column->index != OVSDB_COL_UUID) {
+ ovsdb_jsonrpc_add_monitor_column(mt, column, select,
+ allocated_columns);
+ }
+ }
+ }
+
+ return NULL;
+}
+