summaryrefslogtreecommitdiff
path: root/lib/ovsdb-idl.h
blob: 86fd2bd36f2722958beea00d0891ac68038ac484 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2019 Nicira, Inc.
 * Copyright (C) 2016 Hewlett Packard Enterprise Development LP
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef OVSDB_IDL_H
#define OVSDB_IDL_H 1

/* Open vSwitch Database Interface Definition Language (OVSDB IDL).
 *
 * The OVSDB IDL maintains an in-memory replica of a database.  It issues RPC
 * requests to an OVSDB database server and parses the responses, converting
 * raw JSON into data structures that are easier for clients to digest.  Most
 * notably, references to rows via UUID become C pointers.
 *
 * The IDL always presents a consistent snapshot of the database to its client,
 * that is, it won't present the effects of some part of a transaction applied
 * at the database server without presenting all of its effects.
 *
 * The IDL also assists with issuing database transactions.  The client creates
 * a transaction, manipulates the IDL data structures, and commits or aborts
 * the transaction.  The IDL then composes and issues the necessary JSON-RPC
 * requests and reports to the client whether the transaction completed
 * successfully.
 */

#include <stdbool.h>
#include <stdint.h>
#include "compiler.h"
#include "ovsdb-types.h"
#include "ovsdb-data.h"
#include "openvswitch/list.h"
#include "ovsdb-condition.h"
#include "skiplist.h"

#ifdef __cplusplus
extern "C" {
#endif

struct json;
struct ovsdb_datum;
struct ovsdb_idl_class;
struct ovsdb_idl_row;
struct ovsdb_idl_column;
struct ovsdb_idl_table;
struct ovsdb_idl_table_class;
struct simap;
struct uuid;

struct ovsdb_idl *ovsdb_idl_create(const char *remote,
                                   const struct ovsdb_idl_class *,
                                   bool monitor_everything_by_default,
                                   bool retry);
struct ovsdb_idl *ovsdb_idl_create_unconnected(
    const struct ovsdb_idl_class *, bool monitor_everything_by_default);
void ovsdb_idl_set_remote(struct ovsdb_idl *, const char *remote, bool retry);
void ovsdb_idl_set_shuffle_remotes(struct ovsdb_idl *, bool shuffle);
void ovsdb_idl_set_db_change_aware(struct ovsdb_idl *,
                                   bool set_db_change_aware);
void ovsdb_idl_reset_min_index(struct ovsdb_idl *);
void ovsdb_idl_destroy(struct ovsdb_idl *);

void ovsdb_idl_set_leader_only(struct ovsdb_idl *, bool leader_only);

void ovsdb_idl_run(struct ovsdb_idl *);
void ovsdb_idl_wait(struct ovsdb_idl *);

void ovsdb_idl_get_memory_usage(struct ovsdb_idl *, struct simap *usage);

void ovsdb_idl_set_lock(struct ovsdb_idl *, const char *lock_name);
bool ovsdb_idl_has_lock(const struct ovsdb_idl *);
bool ovsdb_idl_is_lock_contended(const struct ovsdb_idl *);

unsigned int ovsdb_idl_get_seqno(const struct ovsdb_idl *);
bool ovsdb_idl_has_ever_connected(const struct ovsdb_idl *);
void ovsdb_idl_enable_reconnect(struct ovsdb_idl *);
void ovsdb_idl_force_reconnect(struct ovsdb_idl *);
void ovsdb_idl_verify_write_only(struct ovsdb_idl *);

bool ovsdb_idl_is_alive(const struct ovsdb_idl *);
bool ovsdb_idl_is_connected(const struct ovsdb_idl *idl);
int ovsdb_idl_get_last_error(const struct ovsdb_idl *);

void ovsdb_idl_set_probe_interval(const struct ovsdb_idl *, int probe_interval);

void ovsdb_idl_check_consistency(const struct ovsdb_idl *);

const struct ovsdb_idl_class *ovsdb_idl_get_class(const struct ovsdb_idl *);
const struct ovsdb_idl_table_class *ovsdb_idl_table_class_from_column(
    const struct ovsdb_idl_class *, const struct ovsdb_idl_column *);
bool ovsdb_idl_server_has_table(const struct ovsdb_idl *,
                                const struct ovsdb_idl_table_class *);
bool ovsdb_idl_server_has_column(const struct ovsdb_idl *,
                                 const struct ovsdb_idl_column *);

/* Choosing columns and tables to replicate.
 *
 * The client may choose any subset of the columns and tables to replicate,
 * specifying it one of two ways:
 *
 *   - As a deny list (adding the columns or tables to replicate).  To do so,
 *     the client passes false as 'monitor_everything_by_default' to
 *     ovsdb_idl_create() and then calls ovsdb_idl_add_column() and
 *     ovsdb_idl_add_table() for the desired columns and, if necessary, tables.
 *
 *   - As an allow list (replicating all columns and tables except those
 *     explicitly removed).  To do so, the client passes true as
 *     'monitor_everything_by_default' to ovsdb_idl_create() and then calls
 *     ovsdb_idl_omit() to remove columns.
 *
 * There are multiple modes a column may be replicated:
 *
 *   - Read-only.  This is the default.  Whenever the column changes in any
 *     replicated row, the value returned by ovsdb_idl_get_seqno() will change,
 *     letting the client know to look at the replicated data again.
 *
 *   - Write-only.  This is for columns that the client sets and updates but
 *     does not want to be alerted about its own updates (which, at the OVSDB
 *     level, cannot be distinguished from updates made by any other client).
 *     The column will be replicated in the same way as for read-only columns,
 *     but the value returned by ovsdb_idl_get_seqno() will not change when the
 *     column changes, saving wasted CPU time.
 *
 *     (A "write-only" client probably does read the column so that it can know
 *     whether it needs to update it, but it doesn't expect to react to changes
 *     by other clients.)
 *
 *     To mark a replicated column as write-only, a client calls
 *     ovsdb_idl_omit_alert().  (The column must already be replicated one of
 *     the ways described in the previous list.)
 *
 *     This is an optimization only and does not affect behavioral correctness
 *     of an otherwise well-written client.
 *
 *   - Read/write.  In theory, an OVSDB client might both read and write a
 *     column, although OVSDB schemas are usually designed so that any given
 *     client only does one or the other.  This is actually the same as
 *     read/write columns; that is, the client need take no special action.
 */

/* Modes with which the IDL can replicate a column.  See above comment for
 * overview.
 *
 * If no bits are set, the IDL does not replicate the column at all.  The
 * client will always see it with the default value for its type.
 *
 * If OVSDB_IDL_MONITOR is set, then the IDL replicates the column and sets it
 * to to the value in the database.  If OVSDB_IDL_ALERT is also set, then the
 * IDL will change the value returned by ovsdb_idl_get_seqno() when the
 * column's value changes in any row.
 *
 * Typical mode combinations are:
 *
 *   - 0, for a column that a client doesn't care about.  This is the default
 *     for every column in every table, if the client passes false for
 *     'monitor_everything_by_default' to ovsdb_idl_create().
 *
 *   - (OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT), for a column that a client wants
 *     to track and possibly update.  This is the default for every column in
 *     every table, if the client passes true for
 *     'monitor_everything_by_default' to ovsdb_idl_create().
 *
 *   - OVSDB_IDL_MONITOR, for columns that a client treats as "write-only",
 *     that is, it updates them but doesn't want to get alerted about its own
 *     updates.  It also won't be alerted about other clients' updates, so this
 *     is suitable only for use by a client that "owns" a particular column.
 *     Use ovsdb_idl_omit_alert() to set a column that is already replicated to
 *     this mode.
 *
 *   - OVDSB_IDL_ALERT without OVSDB_IDL_MONITOR is not valid.
 *
 *   - (OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT | OVSDB_IDL_TRACK), for a column
 *     that a client wants to track using the change tracking
 *     ovsdb_idl_track_get_*() functions.
 *
 *   - (OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT | OVSDB_IDL_WRITE_CHANGED_ONLY)
 *     is similar to (OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT) except that it
 *     only adds a written column to a transaction if the column's value
 *     has actually changed.
 */
#define OVSDB_IDL_MONITOR (1 << 0) /* Replicate this column? */
#define OVSDB_IDL_ALERT   (1 << 1) /* Alert client when column changes? */
#define OVSDB_IDL_TRACK   (1 << 2) /* Track column changes? */
#define OVSDB_IDL_WRITE_CHANGED_ONLY \
                          (1 << 3) /* Write back only changed columns? */

void ovsdb_idl_add_column(struct ovsdb_idl *, const struct ovsdb_idl_column *);
void ovsdb_idl_add_table(struct ovsdb_idl *,
                         const struct ovsdb_idl_table_class *);

void ovsdb_idl_omit(struct ovsdb_idl *, const struct ovsdb_idl_column *);
void ovsdb_idl_omit_alert(struct ovsdb_idl *, const struct ovsdb_idl_column *);

/* Change tracking.
 *
 * In OVSDB, change tracking is applied at each client in the IDL layer.  This
 * means that when a client makes a request to track changes on a particular
 * table, they are essentially requesting information about the incremental
 * changes to that table from the point in time that the request is made.  Once
 * the client clears tracked changes, that information will no longer be
 * available.
 *
 * The implication of the above is that if a client requires replaying
 * untracked history, it faces the choice of either trying to remember changes
 * itself (which translates into a memory leak) or of being structured with a
 * path for processing the full untracked table as well as a path that
 * processes incremental changes. */
enum ovsdb_idl_change {
    OVSDB_IDL_CHANGE_INSERT,
    OVSDB_IDL_CHANGE_MODIFY,
    OVSDB_IDL_CHANGE_DELETE,
    OVSDB_IDL_CHANGE_MAX
};

/* Row, table sequence numbers */
unsigned int ovsdb_idl_table_get_seqno(
    const struct ovsdb_idl *idl,
    const struct ovsdb_idl_table_class *table_class);
unsigned int ovsdb_idl_row_get_seqno(
    const struct ovsdb_idl_row *row,
    enum ovsdb_idl_change change);

void ovsdb_idl_track_add_column(struct ovsdb_idl *idl,
                                const struct ovsdb_idl_column *column);
void ovsdb_idl_track_add_all(struct ovsdb_idl *idl);
bool ovsdb_idl_track_is_set(struct ovsdb_idl_table *table);
const struct ovsdb_idl_row *ovsdb_idl_track_get_first(
    const struct ovsdb_idl *, const struct ovsdb_idl_table_class *);
const struct ovsdb_idl_row *ovsdb_idl_track_get_next(const struct ovsdb_idl_row *);
bool ovsdb_idl_track_is_updated(const struct ovsdb_idl_row *row,
                                const struct ovsdb_idl_column *column);
void ovsdb_idl_track_clear(struct ovsdb_idl *);

void ovsdb_idl_set_write_changed_only(struct ovsdb_idl *idl,
                                      const struct ovsdb_idl_column *column,
                                      bool enable);
void ovsdb_idl_set_write_changed_only_all(struct ovsdb_idl *idl, bool enable);


/* Reading the database replica. */

const struct ovsdb_idl_row *ovsdb_idl_get_row_for_uuid(
    const struct ovsdb_idl *, const struct ovsdb_idl_table_class *,
    const struct uuid *);
const struct ovsdb_idl_row *ovsdb_idl_first_row(
    const struct ovsdb_idl *, const struct ovsdb_idl_table_class *);
const struct ovsdb_idl_row *ovsdb_idl_next_row(const struct ovsdb_idl_row *);

const struct ovsdb_datum *ovsdb_idl_read(const struct ovsdb_idl_row *,
                                         const struct ovsdb_idl_column *);
const struct ovsdb_datum *ovsdb_idl_get(const struct ovsdb_idl_row *,
                                        const struct ovsdb_idl_column *,
                                        enum ovsdb_atomic_type key_type,
                                        enum ovsdb_atomic_type value_type);
bool ovsdb_idl_is_mutable(const struct ovsdb_idl_row *,
                          const struct ovsdb_idl_column *);

bool ovsdb_idl_row_is_synthetic(const struct ovsdb_idl_row *);

/* Transactions.
 *
 * A transaction may modify the contents of a database by modifying the values
 * of columns, deleting rows, inserting rows, or adding checks that columns in
 * the database have not changed ("verify" operations), through
 * ovsdb_idl_txn_*() functions.  (The OVSDB IDL code generator produces helper
 * functions that internally call the ovsdb_idl_txn_*() functions.  These are
 * likely to be more convenient.)
 *
 * Reading and writing columns and inserting and deleting rows are all
 * straightforward.  The reasons to verify columns are less obvious.
 * Verification is the key to maintaining transactional integrity.  Because
 * OVSDB handles multiple clients, it can happen that between the time that
 * OVSDB client A reads a column and writes a new value, OVSDB client B has
 * written that column.  Client A's write should not ordinarily overwrite
 * client B's, especially if the column in question is a "map" column that
 * contains several more or less independent data items.  If client A adds a
 * "verify" operation before it writes the column, then the transaction fails
 * in case client B modifies it first.  Client A will then see the new value of
 * the column and compose a new transaction based on the new contents written
 * by client B.
 *
 * When a transaction is complete, which must be before the next call to
 * ovsdb_idl_run() on 'idl', call ovsdb_idl_txn_commit() or
 * ovsdb_idl_txn_abort().
 *
 * The life-cycle of a transaction looks like this:
 *
 * 1. Create the transaction and record the initial sequence number:
 *
 *     seqno = ovsdb_idl_get_seqno(idl);
 *     txn = ovsdb_idl_txn_create(idl);
 *
 * 2. Modify the database with ovsdb_idl_txn_*() functions directly or
 *    indirectly.
 *
 * 3. Commit the transaction by calling ovsdb_idl_txn_commit().  The first call
 *    to this function probably returns TXN_INCOMPLETE.  The client must keep
 *    calling again along as this remains true, calling ovsdb_idl_run() in
 *    between to let the IDL do protocol processing.  (If the client doesn't
 *    have anything else to do in the meantime, it can use
 *    ovsdb_idl_txn_commit_block() to avoid having to loop itself.)
 *
 * 4. If the final status is TXN_TRY_AGAIN, wait for ovsdb_idl_get_seqno() to
 *    change from the saved 'seqno' (it's possible that it's already changed,
 *    in which case the client should not wait at all), then start over from
 *    step 1.  Only a call to ovsdb_idl_run() will change the return value of
 *    ovsdb_idl_get_seqno().  (ovsdb_idl_txn_commit_block() calls
 *    ovsdb_idl_run().)
 */

enum ovsdb_idl_txn_status {
    TXN_UNCOMMITTED,            /* Not yet committed or aborted. */
    TXN_UNCHANGED,              /* Transaction didn't include any changes. */
    TXN_INCOMPLETE,             /* Commit in progress, please wait. */
    TXN_ABORTED,                /* ovsdb_idl_txn_abort() called. */
    TXN_SUCCESS,                /* Commit successful. */
    TXN_TRY_AGAIN,              /* Commit failed because a "verify" operation
                                 * reported an inconsistency, due to a network
                                 * problem, or other transient failure.  Wait
                                 * for a change, then try again. */
    TXN_NOT_LOCKED,             /* Server hasn't given us the lock yet. */
    TXN_ERROR                   /* Commit failed due to a hard error. */
};

const char *ovsdb_idl_txn_status_to_string(enum ovsdb_idl_txn_status);

struct ovsdb_idl_txn *ovsdb_idl_txn_create(struct ovsdb_idl *);
void ovsdb_idl_txn_add_comment(struct ovsdb_idl_txn *, const char *, ...)
    OVS_PRINTF_FORMAT (2, 3);
void ovsdb_idl_txn_set_dry_run(struct ovsdb_idl_txn *);
void ovsdb_idl_txn_increment(struct ovsdb_idl_txn *,
                             const struct ovsdb_idl_row *,
                             const struct ovsdb_idl_column *,
                             bool force);
void ovsdb_idl_txn_destroy(struct ovsdb_idl_txn *);
void ovsdb_idl_txn_wait(const struct ovsdb_idl_txn *);
enum ovsdb_idl_txn_status ovsdb_idl_txn_commit(struct ovsdb_idl_txn *);
enum ovsdb_idl_txn_status ovsdb_idl_txn_commit_block(struct ovsdb_idl_txn *);
void ovsdb_idl_txn_abort(struct ovsdb_idl_txn *);

const char *ovsdb_idl_txn_get_error(const struct ovsdb_idl_txn *);

int64_t ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn *);
const struct uuid *ovsdb_idl_txn_get_insert_uuid(const struct ovsdb_idl_txn *,
                                                 const struct uuid *);

void ovsdb_idl_txn_write(const struct ovsdb_idl_row *,
                         const struct ovsdb_idl_column *,
                         struct ovsdb_datum *);
void ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row *,
                               const struct ovsdb_idl_column *,
                               const struct ovsdb_datum *);
void ovsdb_idl_txn_write_partial_map(const struct ovsdb_idl_row *,
                                     const struct ovsdb_idl_column *,
                                     struct ovsdb_datum *);
void ovsdb_idl_txn_delete_partial_map(const struct ovsdb_idl_row *,
                                      const struct ovsdb_idl_column *,
                                      struct ovsdb_datum *);
void ovsdb_idl_txn_write_partial_set(const struct ovsdb_idl_row *,
                                     const struct ovsdb_idl_column *,
                                     struct ovsdb_datum *);
void ovsdb_idl_txn_delete_partial_set(const struct ovsdb_idl_row *,
                                      const struct ovsdb_idl_column *,
                                      struct ovsdb_datum *);
void ovsdb_idl_txn_delete(const struct ovsdb_idl_row *);
const struct ovsdb_idl_row *ovsdb_idl_txn_insert(
    struct ovsdb_idl_txn *, const struct ovsdb_idl_table_class *,
    const struct uuid *);
const struct ovsdb_idl_row *ovsdb_idl_txn_insert_persist_uuid(
    struct ovsdb_idl_txn *txn, const struct ovsdb_idl_table_class *class,
    const struct uuid *uuid);

struct ovsdb_idl *ovsdb_idl_txn_get_idl (struct ovsdb_idl_txn *);
void ovsdb_idl_get_initial_snapshot(struct ovsdb_idl *);


/* ovsdb_idl_loop provides an easy way to manage the transactions related
 * to 'idl' and to cope with different status during transaction. */
struct ovsdb_idl_loop {
    struct ovsdb_idl *idl;
    unsigned int skip_seqno;

    struct ovsdb_idl_txn *committing_txn;
    unsigned int precommit_seqno;

    struct ovsdb_idl_txn *open_txn;

    /* These members allow a client a simple, stateless way to keep track of
     * transactions that commit: when a transaction commits successfully,
     * ovsdb_idl_loop_commit_and_wait() copies 'next_cfg' to 'cur_cfg'.  Thus,
     * the client can set 'next_cfg' to a value that indicates a successful
     * commit and check 'cur_cfg' on each iteration. */
    int64_t cur_cfg;
    int64_t next_cfg;
};

#define OVSDB_IDL_LOOP_INITIALIZER(IDL) { .idl = (IDL) }

void ovsdb_idl_loop_destroy(struct ovsdb_idl_loop *);
struct ovsdb_idl_txn *ovsdb_idl_loop_run(struct ovsdb_idl_loop *);
int ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop *);

/* Conditional Replication
 * =======================
 *
 * By default, when the IDL replicates a particular table in the database, it
 * replicates every row in the table.  These functions allow the client to
 * specify that only selected rows should be replicated, by constructing a
 * per-table condition that specifies the rows to replicate.
 *
 * A condition is a disjunction of clauses.  The condition is true, and thus a
 * row is replicated, if any of the clauses evaluates to true for a given row.
 * (Thus, a condition with no clauses is always false.)
 */

struct ovsdb_idl_condition {
    struct hmap clauses;        /* Contains "struct ovsdb_idl_clause"s. */
    bool is_true;               /* Is the condition unconditionally true? */
};
#define OVSDB_IDL_CONDITION_INIT(CONDITION) \
    { HMAP_INITIALIZER(&(CONDITION)->clauses), false }

void ovsdb_idl_condition_init(struct ovsdb_idl_condition *);
void ovsdb_idl_condition_clear(struct ovsdb_idl_condition *);
void ovsdb_idl_condition_destroy(struct ovsdb_idl_condition *);
void ovsdb_idl_condition_add_clause(struct ovsdb_idl_condition *,
                                    enum ovsdb_function function,
                                    const struct ovsdb_idl_column *column,
                                    const struct ovsdb_datum *arg);
void ovsdb_idl_condition_add_clause_true(struct ovsdb_idl_condition *);
bool ovsdb_idl_condition_is_true(const struct ovsdb_idl_condition *);

unsigned int ovsdb_idl_set_condition(struct ovsdb_idl *,
                                     const struct ovsdb_idl_table_class *,
                                     const struct ovsdb_idl_condition *);

unsigned int ovsdb_idl_get_condition_seqno(const struct ovsdb_idl *);

/* Indexes over one or more columns in the IDL, to retrieve rows matching
 * particular search criteria and to iterate over a subset of rows in a defined
 * order. */

enum ovsdb_index_order {
    OVSDB_INDEX_ASC,            /* 0, 1, 2, ... */
    OVSDB_INDEX_DESC            /* 2, 1, 0, ... */
};

typedef int column_comparator_func(const void *a, const void *b);

struct ovsdb_idl_index_column {
    const struct ovsdb_idl_column *column;
    column_comparator_func *comparer;
    enum ovsdb_index_order order;
};

/* Creating an index. */
struct ovsdb_idl_index *ovsdb_idl_index_create(
    struct ovsdb_idl *, const struct ovsdb_idl_index_column *, size_t n);
struct ovsdb_idl_index *ovsdb_idl_index_create1(
    struct ovsdb_idl *, const struct ovsdb_idl_column *);
struct ovsdb_idl_index *ovsdb_idl_index_create2(
    struct ovsdb_idl *, const struct ovsdb_idl_column *,
    const struct ovsdb_idl_column *);

/* Searching an index. */
struct ovsdb_idl_row *ovsdb_idl_index_find(struct ovsdb_idl_index *,
                                           const struct ovsdb_idl_row *);

/* Iteration over an index.
 *
 * Usually these would be invoked through table-specific wrappers generated
 * by the IDL. */

struct ovsdb_idl_cursor {
    struct ovsdb_idl_index *index;  /* Index being iterated. */
    struct skiplist_node *position; /* Current position in 'index'. */
};

struct ovsdb_idl_cursor ovsdb_idl_cursor_first(struct ovsdb_idl_index *);
struct ovsdb_idl_cursor ovsdb_idl_cursor_first_eq(
    struct ovsdb_idl_index *, const struct ovsdb_idl_row *);
struct ovsdb_idl_cursor ovsdb_idl_cursor_first_ge(
    struct ovsdb_idl_index *, const struct ovsdb_idl_row *);

void ovsdb_idl_cursor_next(struct ovsdb_idl_cursor *);
void ovsdb_idl_cursor_next_eq(struct ovsdb_idl_cursor *);

struct ovsdb_idl_row *ovsdb_idl_cursor_data(struct ovsdb_idl_cursor *);

#ifdef __cplusplus
}
#endif

#endif /* ovsdb-idl.h */