]>
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 | ||
74 | set_program_name(argv[0]); | |
f85f8ebb BP |
75 | time_init(); |
76 | vlog_init(); | |
77 | signal(SIGPIPE, SIG_IGN); | |
78 | process_init(); | |
79 | ||
0b1fae1b | 80 | parse_options(argc, argv, &file_name, &remotes, &unixctl_path); |
f85f8ebb | 81 | |
eb077b26 | 82 | die_if_already_running(); |
95440284 | 83 | daemonize_start(); |
eb077b26 | 84 | |
bd06962a | 85 | error = ovsdb_file_open(file_name, false, &db); |
f85f8ebb BP |
86 | if (error) { |
87 | ovs_fatal(0, "%s", ovsdb_error_to_string(error)); | |
88 | } | |
89 | ||
b93d3b6c | 90 | jsonrpc = ovsdb_jsonrpc_server_create(db); |
0b1fae1b | 91 | set_remotes(jsonrpc, db, &remotes); |
f85f8ebb | 92 | |
aa78de9d | 93 | retval = unixctl_server_create(unixctl_path, &unixctl); |
f85f8ebb BP |
94 | if (retval) { |
95 | ovs_fatal(retval, "could not listen for control connections"); | |
96 | } | |
97 | ||
95440284 | 98 | daemonize_complete(); |
aa78de9d | 99 | |
95440284 | 100 | unixctl_command_register("exit", ovsdb_server_exit, &exiting); |
aa78de9d BP |
101 | |
102 | exiting = false; | |
103 | while (!exiting) { | |
0b1fae1b | 104 | set_remotes(jsonrpc, db, &remotes); |
f85f8ebb BP |
105 | ovsdb_jsonrpc_server_run(jsonrpc); |
106 | unixctl_server_run(unixctl); | |
107 | ovsdb_trigger_run(db, time_msec()); | |
108 | ||
109 | ovsdb_jsonrpc_server_wait(jsonrpc); | |
110 | unixctl_server_wait(unixctl); | |
111 | ovsdb_trigger_wait(db, time_msec()); | |
112 | poll_block(); | |
113 | } | |
114 | ||
115 | return 0; | |
116 | } | |
117 | ||
0b1fae1b BP |
118 | static void |
119 | query_db_remotes(const char *name_, const struct ovsdb *db, | |
120 | struct shash *remotes) | |
121 | { | |
122 | char *name, *db_prefix, *table_name, *column_name; | |
123 | const struct ovsdb_column *column; | |
124 | const struct ovsdb_table *table; | |
125 | const struct ovsdb_row *row; | |
126 | char *save_ptr = NULL; | |
127 | ||
128 | name = xstrdup(name_); | |
129 | db_prefix = strtok_r(name, ":", &save_ptr); | |
130 | table_name = strtok_r(NULL, ",", &save_ptr); | |
131 | column_name = strtok_r(NULL, ",", &save_ptr); | |
132 | if (!table_name || !column_name) { | |
133 | ovs_fatal(0, "remote \"%s\": invalid syntax", name_); | |
134 | } | |
135 | ||
136 | table = ovsdb_get_table(db, table_name); | |
137 | if (!table) { | |
138 | ovs_fatal(0, "remote \"%s\": no table named %s", name_, table_name); | |
139 | } | |
140 | ||
141 | column = ovsdb_table_schema_get_column(table->schema, column_name); | |
142 | if (!column) { | |
143 | ovs_fatal(0, "remote \"%s\": table \"%s\" has no column \"%s\"", | |
144 | name_, table_name, column_name); | |
145 | } | |
146 | ||
147 | if (column->type.key_type != OVSDB_TYPE_STRING | |
148 | || column->type.value_type != OVSDB_TYPE_VOID) { | |
149 | ovs_fatal(0, "remote \"%s\": type of table \"%s\" column \"%s\" is " | |
150 | "not string or set of strings", | |
151 | name_, table_name, column_name); | |
152 | } | |
153 | ||
154 | HMAP_FOR_EACH (row, struct ovsdb_row, hmap_node, &table->rows) { | |
155 | const struct ovsdb_datum *datum; | |
156 | size_t i; | |
157 | ||
158 | datum = &row->fields[column->index]; | |
159 | for (i = 0; i < datum->n; i++) { | |
160 | shash_add_once(remotes, datum->keys[i].string, NULL); | |
161 | } | |
162 | } | |
a0d17251 BP |
163 | |
164 | free(name); | |
0b1fae1b BP |
165 | } |
166 | ||
167 | static void | |
168 | set_remotes(struct ovsdb_jsonrpc_server *jsonrpc, | |
169 | const struct ovsdb *db, struct shash *remotes) | |
170 | { | |
171 | struct shash resolved_remotes; | |
172 | struct shash_node *node; | |
173 | ||
174 | shash_init(&resolved_remotes); | |
175 | SHASH_FOR_EACH (node, remotes) { | |
176 | const char *name = node->name; | |
177 | ||
178 | if (!strncmp(name, "db:", 3)) { | |
179 | query_db_remotes(name, db, &resolved_remotes); | |
180 | } else { | |
181 | shash_add_once(&resolved_remotes, name, NULL); | |
182 | } | |
183 | } | |
184 | ovsdb_jsonrpc_server_set_remotes(jsonrpc, &resolved_remotes); | |
185 | shash_destroy(&resolved_remotes); | |
186 | } | |
187 | ||
188 | ||
aa78de9d BP |
189 | static void |
190 | ovsdb_server_exit(struct unixctl_conn *conn, const char *args UNUSED, | |
191 | void *exiting_) | |
192 | { | |
193 | bool *exiting = exiting_; | |
194 | *exiting = true; | |
195 | unixctl_command_reply(conn, 200, NULL); | |
196 | } | |
197 | ||
f85f8ebb BP |
198 | static void |
199 | parse_options(int argc, char *argv[], char **file_namep, | |
0b1fae1b | 200 | struct shash *remotes, char **unixctl_pathp) |
f85f8ebb BP |
201 | { |
202 | enum { | |
203 | OPT_DUMMY = UCHAR_MAX + 1, | |
0b1fae1b | 204 | OPT_REMOTE, |
aa78de9d | 205 | OPT_UNIXCTL, |
9467fe62 | 206 | OPT_BOOTSTRAP_CA_CERT, |
f85f8ebb BP |
207 | VLOG_OPTION_ENUMS, |
208 | LEAK_CHECKER_OPTION_ENUMS | |
209 | }; | |
210 | static struct option long_options[] = { | |
0b1fae1b | 211 | {"remote", required_argument, 0, OPT_REMOTE}, |
aa78de9d | 212 | {"unixctl", required_argument, 0, OPT_UNIXCTL}, |
f85f8ebb BP |
213 | {"help", no_argument, 0, 'h'}, |
214 | {"version", no_argument, 0, 'V'}, | |
215 | DAEMON_LONG_OPTIONS, | |
216 | VLOG_LONG_OPTIONS, | |
217 | LEAK_CHECKER_LONG_OPTIONS, | |
9467fe62 BP |
218 | #ifdef HAVE_OPENSSL |
219 | {"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT}, | |
220 | STREAM_SSL_LONG_OPTIONS | |
221 | #endif | |
f85f8ebb BP |
222 | {0, 0, 0, 0}, |
223 | }; | |
224 | char *short_options = long_options_to_short_options(long_options); | |
225 | ||
0b1fae1b | 226 | shash_init(remotes); |
f85f8ebb BP |
227 | for (;;) { |
228 | int c; | |
229 | ||
230 | c = getopt_long(argc, argv, short_options, long_options, NULL); | |
231 | if (c == -1) { | |
232 | break; | |
233 | } | |
234 | ||
235 | switch (c) { | |
0b1fae1b BP |
236 | case OPT_REMOTE: |
237 | shash_add_once(remotes, optarg, NULL); | |
f85f8ebb BP |
238 | break; |
239 | ||
aa78de9d BP |
240 | case OPT_UNIXCTL: |
241 | *unixctl_pathp = optarg; | |
242 | break; | |
243 | ||
f85f8ebb BP |
244 | case 'h': |
245 | usage(); | |
246 | ||
247 | case 'V': | |
248 | OVS_PRINT_VERSION(0, 0); | |
249 | exit(EXIT_SUCCESS); | |
250 | ||
251 | VLOG_OPTION_HANDLERS | |
252 | DAEMON_OPTION_HANDLERS | |
253 | LEAK_CHECKER_OPTION_HANDLERS | |
254 | ||
9467fe62 BP |
255 | #ifdef HAVE_OPENSSL |
256 | STREAM_SSL_OPTION_HANDLERS | |
257 | ||
258 | case OPT_BOOTSTRAP_CA_CERT: | |
259 | stream_ssl_set_ca_cert_file(optarg, true); | |
260 | break; | |
261 | #endif | |
262 | ||
263 | ||
f85f8ebb BP |
264 | case '?': |
265 | exit(EXIT_FAILURE); | |
266 | ||
267 | default: | |
268 | abort(); | |
269 | } | |
270 | } | |
271 | free(short_options); | |
272 | ||
273 | argc -= optind; | |
274 | argv += optind; | |
275 | ||
cf3a5d91 | 276 | if (argc > 1) { |
f85f8ebb BP |
277 | ovs_fatal(0, "database file is only non-option argument; " |
278 | "use --help for usage"); | |
cf3a5d91 BP |
279 | } else if (argc < 1) { |
280 | ovs_fatal(0, "missing database file argument; use --help for usage"); | |
f85f8ebb BP |
281 | } |
282 | ||
283 | *file_namep = argv[0]; | |
284 | } | |
285 | ||
286 | static void | |
287 | usage(void) | |
288 | { | |
289 | printf("%s: Open vSwitch database server\n" | |
290 | "usage: %s [OPTIONS] DATABASE\n" | |
291 | "where DATABASE is a database file in ovsdb format.\n", | |
292 | program_name, program_name); | |
293 | printf("\nJSON-RPC options (may be specified any number of times):\n" | |
0b1fae1b | 294 | " --remote=REMOTE connect or listen to REMOTE\n"); |
9467fe62 | 295 | stream_usage("JSON-RPC", true, true, true); |
f85f8ebb BP |
296 | daemon_usage(); |
297 | vlog_usage(); | |
298 | printf("\nOther options:\n" | |
299 | " -h, --help display this help message\n" | |
300 | " -V, --version display version information\n"); | |
301 | leak_checker_usage(); | |
302 | exit(EXIT_SUCCESS); | |
303 | } |