summaryrefslogtreecommitdiff
path: root/lib/db-ctl-base.h
blob: ea7e97b78446f2f6e0a0853d0399898263ea8f4e (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
/*
 * Copyright (c) 2015, 2017 Nicira, Inc.
 *
 * 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 DB_CTL_BASE_H
#define DB_CTL_BASE_H 1

#include "compiler.h"
#include "openvswitch/dynamic-string.h"
#include "openvswitch/shash.h"

struct ctl_context;
struct option;
struct ovsdb_idl;
struct ovsdb_idl_row;
struct ovsdb_idl_txn;
struct ovsdb_symbol_table;
struct table;

/* This library module contains the common parts for ovsdb manipulation
 * (structs, commands and functions).  To utilize this module, user must
 * define the following:
 *
 * - the command syntaxes for each command.  (See 'struct ctl_command_syntax'
 *   for more info)  and regiters them using ctl_register_commands().
 *
 * - the *ctl command context by inheriting the 'struct ctl_context' for
 *   additional commands implemented by user.  (See 'struct ctl_context' for
 *   more info)
*/

/* ctl_fatal() also logs the error, so it is preferred in this file. */
#define ovs_fatal please_use_ctl_fatal_instead_of_ovs_fatal

struct ctl_table_class;
struct ovsdb_idl_class;
struct ovsdb_idl_table_class;
struct cmd_show_table;

/* ctl_init() figures out the number of tables on its own and flags an error if
 * 'ctl_classes' was defined with the wrong number of elements. */
#define ctl_init(idl_class, table_classes, ctl_classes, cmd_show_table, \
                 ctl_exit_func)                                         \
    (BUILD_ASSERT(ARRAY_SIZE(table_classes) == ARRAY_SIZE(ctl_classes)),  \
     ctl_init__(idl_class, ctl_classes, cmd_show_table, ctl_exit_func))
void ctl_init__(const struct ovsdb_idl_class *, const struct ctl_table_class *,
                const struct cmd_show_table *cmd_show_tables,
                void (*ctl_exit_func)(int status));
char *ctl_default_db(void);
void ctl_error(struct ctl_context *, const char *, ...)
OVS_PRINTF_FORMAT(2, 3);
OVS_NO_RETURN void ctl_fatal(const char *, ...) OVS_PRINTF_FORMAT(1, 2);

/* *ctl command syntax structure, to be defined by each command implementation.
 *
 * Execution Path
 * ==============
 *
 * Three stylized functions accompany each of these data structures:
 *
 *               "pre-run"         "run"        "post-run"
 *            ---------------  ------------  -----------------
 * *ctl       ->prerequisites     ->run        ->postprocess
 *
 * Any *ctl command implementation should go through the following execution
 * path:
 *
 *   1. parses user command-line input and finds the corresponding syntax
 *      structures.
 *
 *   2. calls prerequisites() for getting the columns or tables used by each
 *      command.
 *
 *   3. calls run() to execute each command and to generate output.
 *
 *   4. calls postprocess() after output has been committed.  (Only needed
 *      by 'create' command sofar)
 *
 * Execution Context
 * =================
 *
 * Each of the stylized functions requires the 'struct ctl_context' as input
 * to provide context e.g. command-line arguments, table to be modified.  User
 * may define more specific context (by inheriting 'struct ctl_context') and
 * write stylized functions that use it.  In that case, CONTAINER_OF() can
 * be used to cast the generic context to the specific one.
 *
 * */
struct ctl_command_syntax {
    const char *name;           /* e.g. "add-br" */
    int min_args;               /* Min number of arguments following name. */
    int max_args;               /* Max number of arguments following name. */

    /* Names that roughly describe the arguments that the command
     * uses.  These should be similar to the names displayed in the
     * man page or in the help output. */
    const char *arguments;

    /* If nonnull, calls ovsdb_idl_add_column() or ovsdb_idl_add_table() for
     * each column or table in ctx->idl that it uses. */
    void (*prerequisites)(struct ctl_context *ctx);

    /* Does the actual work of the command and puts the command's output, if
     * any, in ctx->output or ctx->table.
     *
     * Alternatively, if some prerequisite of the command is not met and the
     * caller should wait for something to change and then retry, it may set
     * ctx->try_again to true.  (Only the "wait-until" command currently does
     * this.) */
    void (*run)(struct ctl_context *ctx);

    /* If nonnull, called after the transaction has been successfully
     * committed.  ctx->output is the output from the "run" function, which
     * this function may modify and otherwise postprocess as needed.  (Only the
     * "create" command currently does any postprocessing.) */
    void (*postprocess)(struct ctl_context *ctx);

    /* A comma-separated list of supported options, e.g. "--a,--b", or the
     * empty string if the command does not support any options.
     *
     * Arguments are determined by appending special characters to option
     * names:
     *
     *   - Append "=" (e.g. "--id=") for a required argument.
     *
     *   - Append "?" (e.g. "--ovs?") for an optional argument.
     *
     *   - Otherwise an option does not accept an argument. */
    const char *options;

    enum { RO, RW } mode;   /* Does this command modify the database? */
};

/* A command extracted from command-line input plus the structs for
 * output generation. */
struct ctl_command {
    /* Data that remains constant after initialization. */
    const struct ctl_command_syntax *syntax;
    int argc;
    char **argv;
    struct shash options;

    /* Data modified by commands. */
    struct ds output;
    struct table *table;
};

bool ctl_might_write_to_db(const struct ctl_command *, size_t n);
const char *ctl_get_db_cmd_usage(void);

const char *ctl_list_db_tables_usage(void);
void ctl_print_commands(void);
void ctl_print_options(const struct option *);
void ctl_add_cmd_options(struct option **, size_t *n_options_p,
                         size_t *allocated_options_p, int opt_val);
void ctl_register_commands(const struct ctl_command_syntax *);
char * OVS_WARN_UNUSED_RESULT ctl_parse_commands(
    int argc, char *argv[], struct shash *local_options,
    struct ctl_command **commandsp, size_t *n_commandsp);

/* Sometimes, it is desirable to print the table with weak reference to
 * rows in a 'cmd_show_table' table.  In that case, the 'weak_ref_table'
 * should be used and user must define all variables. */
struct weak_ref_table {
    const struct ovsdb_idl_table_class *table;
    const struct ovsdb_idl_column *name_column;
    /* This colum must be a weak reference to the owning
     * 'struct cmd_show_table''s table row. */
    const struct ovsdb_idl_column *wref_column;
};

/* This struct is for organizing the 'show' command output where:
 *
 * - 'table' is the table to show.
 *
 * - if 'name_column' is not null, it is used as the name for each row
 *   in 'table'.
 *
 * - 'columns[]' allows user to specify the print of additional columns
 *   in 'table'.
 *
 * - if 'wref_table' is populated, print 'wref_table.name_column' for
 *   each row in table 'wref_table.table' that has a reference to 'table'
 *   in 'wref_table.wref_column'.  Every field must be populated.
 *
 * */
struct cmd_show_table {
    const struct ovsdb_idl_table_class *table;
    const struct ovsdb_idl_column *name_column;
    const struct ovsdb_idl_column *columns[4]; /* Seems like a good number. */
    const struct weak_ref_table wref_table;
};


/* The base context struct for conducting the common database
 * operations (commands listed in 'db_ctl_commands').  User should
 * define the per-schema context by inheriting this struct as base.
 *
 * Database Caches
 * ===============
 *
 * User may implement caches for contents of the database to facilitate
 * specific commands.  In that case, the common commands defined in
 * 'db_ctl_commands' that may invalidate the cache must call the
 * invalidate_cache().
 *
 **/
struct ctl_context {
    /* Read-only. */
    int argc;
    char **argv;
    struct shash options;

    /* Modifiable state. */
    char *error;
    struct ds output;
    struct table *table;
    struct ovsdb_idl *idl;
    struct ovsdb_idl_txn *txn;
    struct ovsdb_symbol_table *symtab;

    /* For implementation with a cache of the contents of the database,
     * this function will be called when the database is changed and the
     * change makes the cache no longer valid. */
    void (*invalidate_cache_cb)(struct ctl_context *);

    /* A command may set this member to true if some prerequisite is not met
     * and the caller should wait for something to change and then retry. */
    bool try_again;

    /* If set during the context initialization, command implementation
     * may use optimizations that will leave database changes invisible
     * to IDL, e.g. use partial set updates. */
    bool last_command;
};

void ctl_context_init_command(struct ctl_context *, struct ctl_command *,
                              bool last);
void ctl_context_init(struct ctl_context *, struct ctl_command *,
                      struct ovsdb_idl *, struct ovsdb_idl_txn *,
                      struct ovsdb_symbol_table *,
                      void (*invalidate_cache)(struct ctl_context *));
void ctl_context_done_command(struct ctl_context *, struct ctl_command *);
void ctl_context_done(struct ctl_context *, struct ctl_command *);

/* A way to identify a particular row in the database based on a user-provided
 * string.  If all fields are NULL, the struct is ignored.  Otherwise,
 * 'name_column' designates a column whose table is searched for rows that
 * match with the user string.  If 'key' is NULL, then 'name_column' should be
 * a string or integer-valued column; otherwise it should be a map from a
 * string to one of those types and the value corresponding to 'key' is what is
 * matched.  If a matching row is found, then:
 *
 *    - If 'uuid_column' is NULL, the matching row is the final row.
 *
 *    - Otherwise 'uuid_column' must designate a UUID-typed column whose value
 *      refers to exactly one row, which is the final row.
 */
struct ctl_row_id {
    const struct ovsdb_idl_column *name_column;
    const char *key;
    const struct ovsdb_idl_column *uuid_column;
};

struct ctl_table_class {
    struct ctl_row_id row_ids[4];
};

char *ctl_get_row(struct ctl_context *, const struct ovsdb_idl_table_class *,
                  const char *record_id, bool must_exist,
                  const struct ovsdb_idl_row **);

char *ctl_set_column(const char *table_name, const struct ovsdb_idl_row *,
                     const char *arg, struct ovsdb_symbol_table *);

#endif /* db-ctl-base.h */