]>
Commit | Line | Data |
---|---|---|
0b1fae1b | 1 | /* Copyright (c) 2009, 2010 Nicira Networks |
f85f8ebb BP |
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 "ovsdb.h" | |
19 | ||
20 | #include <errno.h> | |
21 | #include <getopt.h> | |
22 | #include <signal.h> | |
eb077b26 | 23 | #include <unistd.h> |
f85f8ebb | 24 | |
0b1fae1b | 25 | #include "column.h" |
f85f8ebb BP |
26 | #include "command-line.h" |
27 | #include "daemon.h" | |
bd06962a | 28 | #include "file.h" |
f85f8ebb BP |
29 | #include "json.h" |
30 | #include "jsonrpc.h" | |
31 | #include "jsonrpc-server.h" | |
32 | #include "leak-checker.h" | |
33 | #include "list.h" | |
0b1fae1b BP |
34 | #include "ovsdb-data.h" |
35 | #include "ovsdb-types.h" | |
f85f8ebb BP |
36 | #include "ovsdb-error.h" |
37 | #include "poll-loop.h" | |
38 | #include "process.h" | |
0b1fae1b | 39 | #include "row.h" |
9467fe62 | 40 | #include "stream-ssl.h" |
f85f8ebb BP |
41 | #include "stream.h" |
42 | #include "svec.h" | |
0b1fae1b | 43 | #include "table.h" |
f85f8ebb BP |
44 | #include "timeval.h" |
45 | #include "trigger.h" | |
46 | #include "util.h" | |
47 | #include "unixctl.h" | |
48 | ||
49 | #include "vlog.h" | |
50 | #define THIS_MODULE VLM_ovsdb_server | |
51 | ||
aa78de9d BP |
52 | static unixctl_cb_func ovsdb_server_exit; |
53 | ||
f85f8ebb | 54 | static void parse_options(int argc, char *argv[], char **file_namep, |
0b1fae1b | 55 | struct shash *remotes, char **unixctl_pathp); |
f85f8ebb BP |
56 | static void usage(void) NO_RETURN; |
57 | ||
0b1fae1b BP |
58 | static void set_remotes(struct ovsdb_jsonrpc_server *jsonrpc, |
59 | const struct ovsdb *db, struct shash *remotes); | |
60 | ||
f85f8ebb BP |
61 | int |
62 | main(int argc, char *argv[]) | |
63 | { | |
aa78de9d | 64 | char *unixctl_path = NULL; |
f85f8ebb BP |
65 | struct unixctl_server *unixctl; |
66 | struct ovsdb_jsonrpc_server *jsonrpc; | |
0b1fae1b | 67 | struct shash remotes; |
f85f8ebb BP |
68 | struct ovsdb_error *error; |
69 | struct ovsdb *db; | |
70 | char *file_name; | |
aa78de9d | 71 | bool exiting; |
f85f8ebb BP |
72 | int retval; |
73 | ||
40f0707c | 74 | proctitle_init(argc, argv); |
f85f8ebb | 75 | set_program_name(argv[0]); |
f85f8ebb BP |
76 | time_init(); |
77 | vlog_init(); | |
78 | signal(SIGPIPE, SIG_IGN); | |
79 | process_init(); | |
80 | ||
0b1fae1b | 81 | parse_options(argc, argv, &file_name, &remotes, &unixctl_path); |
f85f8ebb | 82 | |
eb077b26 | 83 | die_if_already_running(); |
95440284 | 84 | daemonize_start(); |
eb077b26 | 85 | |
bd06962a | 86 | error = ovsdb_file_open(file_name, false, &db); |
f85f8ebb BP |
87 | if (error) { |
88 | ovs_fatal(0, "%s", ovsdb_error_to_string(error)); | |
89 | } | |
90 | ||
b93d3b6c | 91 | jsonrpc = ovsdb_jsonrpc_server_create(db); |
0b1fae1b | 92 | set_remotes(jsonrpc, db, &remotes); |
f85f8ebb | 93 | |
aa78de9d | 94 | retval = unixctl_server_create(unixctl_path, &unixctl); |
f85f8ebb | 95 | if (retval) { |
4d12270a | 96 | exit(EXIT_FAILURE); |
f85f8ebb BP |
97 | } |
98 | ||
95440284 | 99 | daemonize_complete(); |
aa78de9d | 100 | |
95440284 | 101 | unixctl_command_register("exit", ovsdb_server_exit, &exiting); |
aa78de9d BP |
102 | |
103 | exiting = false; | |
104 | while (!exiting) { | |
0b1fae1b | 105 | set_remotes(jsonrpc, db, &remotes); |
f85f8ebb BP |
106 | ovsdb_jsonrpc_server_run(jsonrpc); |
107 | unixctl_server_run(unixctl); | |
108 | ovsdb_trigger_run(db, time_msec()); | |
109 | ||
110 | ovsdb_jsonrpc_server_wait(jsonrpc); | |
111 | unixctl_server_wait(unixctl); | |
112 | ovsdb_trigger_wait(db, time_msec()); | |
113 | poll_block(); | |
114 | } | |
23935e8b BP |
115 | ovsdb_jsonrpc_server_destroy(jsonrpc); |
116 | ovsdb_destroy(db); | |
117 | shash_destroy(&remotes); | |
118 | unixctl_server_destroy(unixctl); | |
f85f8ebb BP |
119 | |
120 | return 0; | |
121 | } | |
122 | ||
0b1fae1b BP |
123 | static void |
124 | query_db_remotes(const char *name_, const struct ovsdb *db, | |
125 | struct shash *remotes) | |
126 | { | |
b0ef0551 | 127 | char *name, *table_name, *column_name; |
0b1fae1b BP |
128 | const struct ovsdb_column *column; |
129 | const struct ovsdb_table *table; | |
130 | const struct ovsdb_row *row; | |
131 | char *save_ptr = NULL; | |
132 | ||
133 | name = xstrdup(name_); | |
b0ef0551 | 134 | strtok_r(name, ":", &save_ptr); /* "db:" */ |
0b1fae1b BP |
135 | table_name = strtok_r(NULL, ",", &save_ptr); |
136 | column_name = strtok_r(NULL, ",", &save_ptr); | |
137 | if (!table_name || !column_name) { | |
138 | ovs_fatal(0, "remote \"%s\": invalid syntax", name_); | |
139 | } | |
140 | ||
141 | table = ovsdb_get_table(db, table_name); | |
142 | if (!table) { | |
143 | ovs_fatal(0, "remote \"%s\": no table named %s", name_, table_name); | |
144 | } | |
145 | ||
146 | column = ovsdb_table_schema_get_column(table->schema, column_name); | |
147 | if (!column) { | |
148 | ovs_fatal(0, "remote \"%s\": table \"%s\" has no column \"%s\"", | |
149 | name_, table_name, column_name); | |
150 | } | |
151 | ||
bd76d25d BP |
152 | if (column->type.key.type != OVSDB_TYPE_STRING |
153 | || column->type.value.type != OVSDB_TYPE_VOID) { | |
0b1fae1b BP |
154 | ovs_fatal(0, "remote \"%s\": type of table \"%s\" column \"%s\" is " |
155 | "not string or set of strings", | |
156 | name_, table_name, column_name); | |
157 | } | |
158 | ||
159 | HMAP_FOR_EACH (row, struct ovsdb_row, hmap_node, &table->rows) { | |
160 | const struct ovsdb_datum *datum; | |
161 | size_t i; | |
162 | ||
163 | datum = &row->fields[column->index]; | |
164 | for (i = 0; i < datum->n; i++) { | |
165 | shash_add_once(remotes, datum->keys[i].string, NULL); | |
166 | } | |
167 | } | |
a0d17251 BP |
168 | |
169 | free(name); | |
0b1fae1b BP |
170 | } |
171 | ||
172 | static void | |
173 | set_remotes(struct ovsdb_jsonrpc_server *jsonrpc, | |
174 | const struct ovsdb *db, struct shash *remotes) | |
175 | { | |
176 | struct shash resolved_remotes; | |
177 | struct shash_node *node; | |
178 | ||
179 | shash_init(&resolved_remotes); | |
180 | SHASH_FOR_EACH (node, remotes) { | |
181 | const char *name = node->name; | |
182 | ||
183 | if (!strncmp(name, "db:", 3)) { | |
184 | query_db_remotes(name, db, &resolved_remotes); | |
185 | } else { | |
186 | shash_add_once(&resolved_remotes, name, NULL); | |
187 | } | |
188 | } | |
189 | ovsdb_jsonrpc_server_set_remotes(jsonrpc, &resolved_remotes); | |
190 | shash_destroy(&resolved_remotes); | |
191 | } | |
192 | ||
193 | ||
aa78de9d | 194 | static void |
c69ee87c | 195 | ovsdb_server_exit(struct unixctl_conn *conn, const char *args OVS_UNUSED, |
aa78de9d BP |
196 | void *exiting_) |
197 | { | |
198 | bool *exiting = exiting_; | |
199 | *exiting = true; | |
200 | unixctl_command_reply(conn, 200, NULL); | |
201 | } | |
202 | ||
f85f8ebb BP |
203 | static void |
204 | parse_options(int argc, char *argv[], char **file_namep, | |
0b1fae1b | 205 | struct shash *remotes, char **unixctl_pathp) |
f85f8ebb BP |
206 | { |
207 | enum { | |
208 | OPT_DUMMY = UCHAR_MAX + 1, | |
0b1fae1b | 209 | OPT_REMOTE, |
aa78de9d | 210 | OPT_UNIXCTL, |
9467fe62 | 211 | OPT_BOOTSTRAP_CA_CERT, |
f85f8ebb BP |
212 | VLOG_OPTION_ENUMS, |
213 | LEAK_CHECKER_OPTION_ENUMS | |
214 | }; | |
215 | static struct option long_options[] = { | |
0b1fae1b | 216 | {"remote", required_argument, 0, OPT_REMOTE}, |
aa78de9d | 217 | {"unixctl", required_argument, 0, OPT_UNIXCTL}, |
f85f8ebb BP |
218 | {"help", no_argument, 0, 'h'}, |
219 | {"version", no_argument, 0, 'V'}, | |
220 | DAEMON_LONG_OPTIONS, | |
221 | VLOG_LONG_OPTIONS, | |
222 | LEAK_CHECKER_LONG_OPTIONS, | |
9467fe62 BP |
223 | #ifdef HAVE_OPENSSL |
224 | {"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT}, | |
225 | STREAM_SSL_LONG_OPTIONS | |
226 | #endif | |
f85f8ebb BP |
227 | {0, 0, 0, 0}, |
228 | }; | |
229 | char *short_options = long_options_to_short_options(long_options); | |
230 | ||
0b1fae1b | 231 | shash_init(remotes); |
f85f8ebb BP |
232 | for (;;) { |
233 | int c; | |
234 | ||
235 | c = getopt_long(argc, argv, short_options, long_options, NULL); | |
236 | if (c == -1) { | |
237 | break; | |
238 | } | |
239 | ||
240 | switch (c) { | |
0b1fae1b BP |
241 | case OPT_REMOTE: |
242 | shash_add_once(remotes, optarg, NULL); | |
f85f8ebb BP |
243 | break; |
244 | ||
aa78de9d BP |
245 | case OPT_UNIXCTL: |
246 | *unixctl_pathp = optarg; | |
247 | break; | |
248 | ||
f85f8ebb BP |
249 | case 'h': |
250 | usage(); | |
251 | ||
252 | case 'V': | |
253 | OVS_PRINT_VERSION(0, 0); | |
254 | exit(EXIT_SUCCESS); | |
255 | ||
256 | VLOG_OPTION_HANDLERS | |
257 | DAEMON_OPTION_HANDLERS | |
258 | LEAK_CHECKER_OPTION_HANDLERS | |
259 | ||
9467fe62 BP |
260 | #ifdef HAVE_OPENSSL |
261 | STREAM_SSL_OPTION_HANDLERS | |
262 | ||
263 | case OPT_BOOTSTRAP_CA_CERT: | |
264 | stream_ssl_set_ca_cert_file(optarg, true); | |
265 | break; | |
266 | #endif | |
267 | ||
268 | ||
f85f8ebb BP |
269 | case '?': |
270 | exit(EXIT_FAILURE); | |
271 | ||
272 | default: | |
273 | abort(); | |
274 | } | |
275 | } | |
276 | free(short_options); | |
277 | ||
278 | argc -= optind; | |
279 | argv += optind; | |
280 | ||
cf3a5d91 | 281 | if (argc > 1) { |
f85f8ebb BP |
282 | ovs_fatal(0, "database file is only non-option argument; " |
283 | "use --help for usage"); | |
cf3a5d91 BP |
284 | } else if (argc < 1) { |
285 | ovs_fatal(0, "missing database file argument; use --help for usage"); | |
f85f8ebb BP |
286 | } |
287 | ||
288 | *file_namep = argv[0]; | |
289 | } | |
290 | ||
291 | static void | |
292 | usage(void) | |
293 | { | |
294 | printf("%s: Open vSwitch database server\n" | |
295 | "usage: %s [OPTIONS] DATABASE\n" | |
296 | "where DATABASE is a database file in ovsdb format.\n", | |
297 | program_name, program_name); | |
298 | printf("\nJSON-RPC options (may be specified any number of times):\n" | |
0b1fae1b | 299 | " --remote=REMOTE connect or listen to REMOTE\n"); |
9467fe62 | 300 | stream_usage("JSON-RPC", true, true, true); |
f85f8ebb BP |
301 | daemon_usage(); |
302 | vlog_usage(); | |
303 | printf("\nOther options:\n" | |
304 | " -h, --help display this help message\n" | |
305 | " -V, --version display version information\n"); | |
306 | leak_checker_usage(); | |
307 | exit(EXIT_SUCCESS); | |
308 | } |