]>
Commit | Line | Data |
---|---|---|
c75d1511 | 1 | /* |
3f5b5f7b | 2 | * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc. |
c75d1511 BP |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at: | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | */ | |
16 | ||
17 | #include <config.h> | |
18 | ||
ad83bfa6 | 19 | #include <ctype.h> |
c75d1511 | 20 | #include <errno.h> |
ad83bfa6 | 21 | #include <float.h> |
c75d1511 BP |
22 | #include <getopt.h> |
23 | #include <inttypes.h> | |
24 | #include <signal.h> | |
25 | #include <stdarg.h> | |
26 | #include <stdlib.h> | |
27 | #include <string.h> | |
6d5abe94 | 28 | #include <unistd.h> |
c75d1511 | 29 | |
07ff77cc AW |
30 | #include "db-ctl-base.h" |
31 | ||
c75d1511 BP |
32 | #include "command-line.h" |
33 | #include "compiler.h" | |
feb38b6d | 34 | #include "dirs.h" |
8a777cf6 | 35 | #include "fatal-signal.h" |
a341ee57 | 36 | #include "hash.h" |
45339539 | 37 | #include "openvswitch/dynamic-string.h" |
ee89ea7b | 38 | #include "openvswitch/json.h" |
45339539 WT |
39 | #include "openvswitch/ofp-parse.h" |
40 | #include "openvswitch/poll-loop.h" | |
41 | #include "openvswitch/vconn.h" | |
42 | #include "openvswitch/vlog.h" | |
ad83bfa6 | 43 | #include "ovsdb-data.h" |
c75d1511 | 44 | #include "ovsdb-idl.h" |
f8ff4bc4 | 45 | #include "process.h" |
45339539 | 46 | #include "simap.h" |
ae9a3235 | 47 | #include "stream.h" |
218a6f59 | 48 | #include "stream-ssl.h" |
a699f614 | 49 | #include "smap.h" |
b3c01ed3 | 50 | #include "sset.h" |
dfbe07ba | 51 | #include "svec.h" |
eaa67ba8 | 52 | #include "lib/vswitch-idl.h" |
e051b42c | 53 | #include "table.h" |
c75d1511 BP |
54 | #include "timeval.h" |
55 | #include "util.h" | |
5136ce49 | 56 | |
d98e6007 | 57 | VLOG_DEFINE_THIS_MODULE(vsctl); |
c75d1511 | 58 | |
f8ff4bc4 BP |
59 | struct vsctl_context; |
60 | ||
c75d1511 BP |
61 | /* --db: The database server to contact. */ |
62 | static const char *db; | |
63 | ||
64 | /* --oneline: Write each command's output as a single line? */ | |
65 | static bool oneline; | |
66 | ||
577aebdf BP |
67 | /* --dry-run: Do not commit any changes. */ |
68 | static bool dry_run; | |
69 | ||
b54e22e9 BP |
70 | /* --no-wait: Wait for ovs-vswitchd to reload its configuration? */ |
71 | static bool wait_for_reload = true; | |
72 | ||
a39a859a | 73 | /* --timeout: Time to wait for a connection to 'db'. */ |
cbcf40a8 | 74 | static unsigned int timeout; |
a39a859a | 75 | |
fba6bd1d BP |
76 | /* --retry: If true, ovs-vsctl will retry connecting to the database forever. |
77 | * If false and --db says to use an active connection method (e.g. "unix:", | |
78 | * "tcp:", "ssl:"), then ovs-vsctl will try to connect once and exit with an | |
79 | * error if the database server cannot be contacted (e.g. ovsdb-server is not | |
80 | * running). | |
81 | * | |
82 | * Regardless of this setting, --timeout always limits how long ovs-vsctl will | |
83 | * wait. */ | |
84 | static bool retry; | |
85 | ||
817db730 BP |
86 | /* --leader-only, --no-leader-only: Only accept the leader in a cluster. |
87 | * | |
88 | * In a real Open vSwitch environment, it doesn't make much sense to cluster | |
89 | * the Open vSwitch database. This option exists to enable using ovs-vsctl to | |
90 | * test OVSDB's clustering feature. */ | |
91 | static int leader_only = true; | |
92 | ||
93 | /* --shuffle-remotes, --no-shuffle-remotes: Shuffle the order of remotes that | |
94 | * are specified in the connetion method string. | |
95 | * | |
96 | * In a real Open vSwitch environment, it doesn't make much sense to cluster | |
97 | * the Open vSwitch database. This option exists to enable using ovs-vsctl to | |
98 | * test OVSDB's clustering feature. */ | |
99 | static int shuffle_remotes = true; | |
100 | ||
e051b42c BP |
101 | /* Format for table output. */ |
102 | static struct table_style table_style = TABLE_STYLE_DEFAULT; | |
103 | ||
07ff77cc | 104 | static void vsctl_cmd_init(void); |
ce6f1d1f AZ |
105 | |
106 | /* The IDL we're using and the current transaction, if any. | |
107 | * This is for use by vsctl_exit() only, to allow it to clean up. | |
108 | * Other code should use its context arguments. */ | |
109 | static struct ovsdb_idl *the_idl; | |
110 | static struct ovsdb_idl_txn *the_idl_txn; | |
111 | OVS_NO_RETURN static void vsctl_exit(int status); | |
112 | ||
cab50449 | 113 | OVS_NO_RETURN static void usage(void); |
401d5a6d | 114 | static void parse_options(int argc, char *argv[], struct shash *local_options); |
07ff77cc | 115 | static void run_prerequisites(struct ctl_command[], size_t n_commands, |
e5e12280 | 116 | struct ovsdb_idl *); |
2335ee93 | 117 | static bool do_vsctl(const char *args, struct ctl_command *, size_t n, |
854a94d9 | 118 | struct ovsdb_idl *); |
c75d1511 | 119 | |
07ff77cc | 120 | /* post_db_reload_check frame work is to allow ovs-vsctl to do additional |
c3ccfe98 AZ |
121 | * checks after OVSDB transactions are successfully recorded and reload by |
122 | * ovs-vswitchd. | |
123 | * | |
124 | * For example, When a new interface is added to OVSDB, ovs-vswitchd will | |
125 | * either store a positive values on successful implementing the new | |
126 | * interface, or -1 on failure. | |
127 | * | |
b2ffb17c | 128 | * Unless --no-wait command line option is specified, |
c3ccfe98 AZ |
129 | * post_db_reload_do_checks() is called right after any configuration |
130 | * changes is picked up (i.e. reload) by ovs-vswitchd. Any error detected | |
131 | * post OVSDB reload is reported as ovs-vsctl errors. OVS-vswitchd logs | |
132 | * more detailed messages about those errors. | |
133 | * | |
134 | * Current implementation only check for Post OVSDB reload failures on new | |
135 | * interface additions with 'add-br' and 'add-port' commands. | |
136 | * | |
137 | * post_db_reload_expect_iface() | |
138 | * | |
139 | * keep track of interfaces to be checked post OVSDB reload. */ | |
140 | static void post_db_reload_check_init(void); | |
141 | static void post_db_reload_do_checks(const struct vsctl_context *); | |
142 | static void post_db_reload_expect_iface(const struct ovsrec_interface *); | |
143 | ||
144 | static struct uuid *neoteric_ifaces; | |
145 | static size_t n_neoteric_ifaces; | |
146 | static size_t allocated_neoteric_ifaces; | |
147 | ||
c75d1511 BP |
148 | int |
149 | main(int argc, char *argv[]) | |
150 | { | |
151 | struct ovsdb_idl *idl; | |
07ff77cc | 152 | struct ctl_command *commands; |
401d5a6d | 153 | struct shash local_options; |
854a94d9 | 154 | unsigned int seqno; |
f8ff4bc4 | 155 | size_t n_commands; |
c75d1511 BP |
156 | |
157 | set_program_name(argv[0]); | |
8a777cf6 | 158 | fatal_ignore_sigpipe(); |
480ce8ab | 159 | vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN); |
45863ce5 | 160 | vlog_set_levels_from_string_assert("reconnect:warn"); |
f8ff4bc4 | 161 | |
07ff77cc AW |
162 | vsctl_cmd_init(); |
163 | ||
f8ff4bc4 | 164 | /* Parse command line. */ |
15f6255f | 165 | char *args = process_escape_args(argv); |
401d5a6d BP |
166 | shash_init(&local_options); |
167 | parse_options(argc, argv, &local_options); | |
a95199f2 JS |
168 | char *error = ctl_parse_commands(argc - optind, argv + optind, |
169 | &local_options, &commands, &n_commands); | |
170 | if (error) { | |
171 | ctl_fatal("%s", error); | |
172 | } | |
15f6255f BP |
173 | VLOG(ctl_might_write_to_db(commands, n_commands) ? VLL_INFO : VLL_DBG, |
174 | "Called as %s", args); | |
c75d1511 | 175 | |
9551e80b | 176 | ctl_timeout_setup(timeout); |
a39a859a | 177 | |
e5e12280 | 178 | /* Initialize IDL. */ |
817db730 BP |
179 | idl = the_idl = ovsdb_idl_create_unconnected(&ovsrec_idl_class, false); |
180 | ovsdb_idl_set_shuffle_remotes(idl, shuffle_remotes); | |
181 | ovsdb_idl_set_remote(idl, db, retry); | |
182 | ovsdb_idl_set_leader_only(idl, leader_only); | |
e5e12280 BP |
183 | run_prerequisites(commands, n_commands, idl); |
184 | ||
854a94d9 BP |
185 | /* Execute the commands. |
186 | * | |
187 | * 'seqno' is the database sequence number for which we last tried to | |
188 | * execute our transaction. There's no point in trying to commit more than | |
189 | * once for any given sequence number, because if the transaction fails | |
190 | * it's because the database changed and we need to obtain an up-to-date | |
191 | * view of the database before we try the transaction again. */ | |
192 | seqno = ovsdb_idl_get_seqno(idl); | |
c75d1511 | 193 | for (;;) { |
854a94d9 | 194 | ovsdb_idl_run(idl); |
fba6bd1d BP |
195 | if (!ovsdb_idl_is_alive(idl)) { |
196 | int retval = ovsdb_idl_get_last_error(idl); | |
07ff77cc | 197 | ctl_fatal("%s: database connection failed (%s)", |
fba6bd1d BP |
198 | db, ovs_retval_to_string(retval)); |
199 | } | |
854a94d9 BP |
200 | |
201 | if (seqno != ovsdb_idl_get_seqno(idl)) { | |
202 | seqno = ovsdb_idl_get_seqno(idl); | |
2335ee93 BP |
203 | if (do_vsctl(args, commands, n_commands, idl)) { |
204 | free(args); | |
205 | exit(EXIT_SUCCESS); | |
206 | } | |
c75d1511 BP |
207 | } |
208 | ||
854a94d9 | 209 | if (seqno == ovsdb_idl_get_seqno(idl)) { |
4fdfe5cc BP |
210 | ovsdb_idl_wait(idl); |
211 | poll_block(); | |
212 | } | |
c75d1511 BP |
213 | } |
214 | } | |
215 | ||
216 | static void | |
401d5a6d | 217 | parse_options(int argc, char *argv[], struct shash *local_options) |
c75d1511 BP |
218 | { |
219 | enum { | |
220 | OPT_DB = UCHAR_MAX + 1, | |
221 | OPT_ONELINE, | |
0c3dd1e1 | 222 | OPT_NO_SYSLOG, |
577aebdf | 223 | OPT_NO_WAIT, |
e26b5a06 | 224 | OPT_DRY_RUN, |
6b777e47 | 225 | OPT_BOOTSTRAP_CA_CERT, |
218a6f59 | 226 | OPT_PEER_CA_CERT, |
401d5a6d | 227 | OPT_LOCAL, |
fba6bd1d | 228 | OPT_RETRY, |
95e4a97a PA |
229 | OPT_COMMANDS, |
230 | OPT_OPTIONS, | |
e051b42c | 231 | VLOG_OPTION_ENUMS, |
e18a1d08 ER |
232 | TABLE_OPTION_ENUMS, |
233 | SSL_OPTION_ENUMS, | |
c75d1511 | 234 | }; |
401d5a6d | 235 | static const struct option global_long_options[] = { |
e3c17733 BP |
236 | {"db", required_argument, NULL, OPT_DB}, |
237 | {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG}, | |
238 | {"no-wait", no_argument, NULL, OPT_NO_WAIT}, | |
239 | {"dry-run", no_argument, NULL, OPT_DRY_RUN}, | |
240 | {"oneline", no_argument, NULL, OPT_ONELINE}, | |
241 | {"timeout", required_argument, NULL, 't'}, | |
fba6bd1d | 242 | {"retry", no_argument, NULL, OPT_RETRY}, |
e3c17733 | 243 | {"help", no_argument, NULL, 'h'}, |
95e4a97a PA |
244 | {"commands", no_argument, NULL, OPT_COMMANDS}, |
245 | {"options", no_argument, NULL, OPT_OPTIONS}, | |
817db730 BP |
246 | {"leader-only", no_argument, &leader_only, true}, |
247 | {"no-leader-only", no_argument, &leader_only, false}, | |
248 | {"shuffle-remotes", no_argument, &shuffle_remotes, true}, | |
249 | {"no-shuffle-remotes", no_argument, &shuffle_remotes, false}, | |
e3c17733 | 250 | {"version", no_argument, NULL, 'V'}, |
e26b5a06 | 251 | VLOG_LONG_OPTIONS, |
e051b42c | 252 | TABLE_LONG_OPTIONS, |
bf8f2167 | 253 | STREAM_SSL_LONG_OPTIONS, |
6b777e47 | 254 | {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT}, |
e3c17733 BP |
255 | {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT}, |
256 | {NULL, 0, NULL, 0}, | |
c75d1511 | 257 | }; |
401d5a6d | 258 | const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1; |
a2a9d2d9 | 259 | char *tmp, *short_options; |
c75d1511 | 260 | |
51a73ff0 | 261 | struct option *options; |
401d5a6d BP |
262 | size_t allocated_options; |
263 | size_t n_options; | |
264 | size_t i; | |
265 | ||
5f383751 | 266 | tmp = ovs_cmdl_long_options_to_short_options(global_long_options); |
a2a9d2d9 BP |
267 | short_options = xasprintf("+%s", tmp); |
268 | free(tmp); | |
342045e1 | 269 | |
401d5a6d BP |
270 | /* We want to parse both global and command-specific options here, but |
271 | * getopt_long() isn't too convenient for the job. We copy our global | |
272 | * options into a dynamic array, then append all of the command-specific | |
273 | * options. */ | |
274 | options = xmemdup(global_long_options, sizeof global_long_options); | |
275 | allocated_options = ARRAY_SIZE(global_long_options); | |
276 | n_options = n_global_long_options; | |
51a73ff0 | 277 | ctl_add_cmd_options(&options, &n_options, &allocated_options, OPT_LOCAL); |
e051b42c | 278 | |
c75d1511 | 279 | for (;;) { |
401d5a6d | 280 | int idx; |
c75d1511 BP |
281 | int c; |
282 | ||
401d5a6d | 283 | c = getopt_long(argc, argv, short_options, options, &idx); |
c75d1511 BP |
284 | if (c == -1) { |
285 | break; | |
286 | } | |
287 | ||
288 | switch (c) { | |
289 | case OPT_DB: | |
290 | db = optarg; | |
291 | break; | |
292 | ||
293 | case OPT_ONELINE: | |
294 | oneline = true; | |
295 | break; | |
296 | ||
dfbe07ba | 297 | case OPT_NO_SYSLOG: |
922fed06 | 298 | vlog_set_levels(&this_module, VLF_SYSLOG, VLL_WARN); |
dfbe07ba BP |
299 | break; |
300 | ||
0c3dd1e1 | 301 | case OPT_NO_WAIT: |
b54e22e9 | 302 | wait_for_reload = false; |
0c3dd1e1 BP |
303 | break; |
304 | ||
577aebdf BP |
305 | case OPT_DRY_RUN: |
306 | dry_run = true; | |
307 | break; | |
308 | ||
401d5a6d BP |
309 | case OPT_LOCAL: |
310 | if (shash_find(local_options, options[idx].name)) { | |
07ff77cc | 311 | ctl_fatal("'%s' option specified multiple times", |
401d5a6d BP |
312 | options[idx].name); |
313 | } | |
314 | shash_add_nocopy(local_options, | |
315 | xasprintf("--%s", options[idx].name), | |
2225c0b9 | 316 | nullable_xstrdup(optarg)); |
401d5a6d BP |
317 | break; |
318 | ||
c75d1511 BP |
319 | case 'h': |
320 | usage(); | |
321 | ||
95e4a97a | 322 | case OPT_COMMANDS: |
51a73ff0 | 323 | ctl_print_commands(); |
73c7216a | 324 | /* fall through */ |
95e4a97a PA |
325 | |
326 | case OPT_OPTIONS: | |
51a73ff0 | 327 | ctl_print_options(global_long_options); |
73c7216a | 328 | /* fall through */ |
95e4a97a | 329 | |
c75d1511 | 330 | case 'V': |
55d5bb44 | 331 | ovs_print_version(0, 0); |
c51513a2 | 332 | printf("DB Schema %s\n", ovsrec_get_db_version()); |
c75d1511 BP |
333 | exit(EXIT_SUCCESS); |
334 | ||
342045e1 | 335 | case 't': |
cbcf40a8 IM |
336 | if (!str_to_uint(optarg, 10, &timeout) || !timeout) { |
337 | ctl_fatal("value %s on -t or --timeout is invalid", optarg); | |
342045e1 BP |
338 | } |
339 | break; | |
340 | ||
fba6bd1d BP |
341 | case OPT_RETRY: |
342 | retry = true; | |
343 | break; | |
344 | ||
e26b5a06 | 345 | VLOG_OPTION_HANDLERS |
e051b42c | 346 | TABLE_OPTION_HANDLERS(&table_style) |
c75d1511 | 347 | |
218a6f59 BP |
348 | STREAM_SSL_OPTION_HANDLERS |
349 | ||
350 | case OPT_PEER_CA_CERT: | |
351 | stream_ssl_set_peer_ca_cert_file(optarg); | |
352 | break; | |
218a6f59 | 353 | |
6b777e47 GS |
354 | case OPT_BOOTSTRAP_CA_CERT: |
355 | stream_ssl_set_ca_cert_file(optarg, true); | |
356 | break; | |
357 | ||
c75d1511 BP |
358 | case '?': |
359 | exit(EXIT_FAILURE); | |
360 | ||
817db730 BP |
361 | case 0: |
362 | break; | |
363 | ||
c75d1511 BP |
364 | default: |
365 | abort(); | |
366 | } | |
367 | } | |
a2a9d2d9 | 368 | free(short_options); |
c75d1511 BP |
369 | |
370 | if (!db) { | |
51a73ff0 | 371 | db = ctl_default_db(); |
c75d1511 | 372 | } |
401d5a6d BP |
373 | |
374 | for (i = n_global_long_options; options[i].name; i++) { | |
375 | free(CONST_CAST(char *, options[i].name)); | |
376 | } | |
377 | free(options); | |
c75d1511 BP |
378 | } |
379 | ||
380 | static void | |
381 | usage(void) | |
382 | { | |
8f7501e8 BP |
383 | printf("\ |
384 | %s: ovs-vswitchd management utility\n\ | |
385 | usage: %s [OPTIONS] COMMAND [ARG...]\n\ | |
386 | \n\ | |
ae9a3235 BP |
387 | Open vSwitch commands:\n\ |
388 | init initialize database, if not yet initialized\n\ | |
9b1735a7 | 389 | show print overview of database contents\n\ |
ae9a3235 BP |
390 | emer-reset reset configuration to clean state\n\ |
391 | \n\ | |
8f7501e8 BP |
392 | Bridge commands:\n\ |
393 | add-br BRIDGE create a new bridge named BRIDGE\n\ | |
394 | add-br BRIDGE PARENT VLAN create new fake BRIDGE in PARENT on VLAN\n\ | |
395 | del-br BRIDGE delete BRIDGE and all of its ports\n\ | |
396 | list-br print the names of all the bridges\n\ | |
b5fcae50 | 397 | br-exists BRIDGE exit 2 if BRIDGE does not exist\n\ |
8f7501e8 BP |
398 | br-to-vlan BRIDGE print the VLAN which BRIDGE is on\n\ |
399 | br-to-parent BRIDGE print the parent of BRIDGE\n\ | |
400 | br-set-external-id BRIDGE KEY VALUE set KEY on BRIDGE to VALUE\n\ | |
401 | br-set-external-id BRIDGE KEY unset KEY on BRIDGE\n\ | |
402 | br-get-external-id BRIDGE KEY print value of KEY on BRIDGE\n\ | |
403 | br-get-external-id BRIDGE list key-value pairs on BRIDGE\n\ | |
404 | \n\ | |
ae9a3235 | 405 | Port commands (a bond is considered to be a single port):\n\ |
8f7501e8 BP |
406 | list-ports BRIDGE print the names of all the ports on BRIDGE\n\ |
407 | add-port BRIDGE PORT add network device PORT to BRIDGE\n\ | |
408 | add-bond BRIDGE PORT IFACE... add bonded port PORT in BRIDGE from IFACES\n\ | |
409 | del-port [BRIDGE] PORT delete PORT (which may be bonded) from BRIDGE\n\ | |
410 | port-to-br PORT print name of bridge that contains PORT\n\ | |
8f7501e8 BP |
411 | \n\ |
412 | Interface commands (a bond consists of multiple interfaces):\n\ | |
413 | list-ifaces BRIDGE print the names of all interfaces on BRIDGE\n\ | |
414 | iface-to-br IFACE print name of bridge that contains IFACE\n\ | |
8f7501e8 BP |
415 | \n\ |
416 | Controller commands:\n\ | |
a892775d BP |
417 | get-controller BRIDGE print the controllers for BRIDGE\n\ |
418 | del-controller BRIDGE delete the controllers for BRIDGE\n\ | |
3ffed5cb | 419 | [--inactivity-probe=MSECS]\n\ |
a892775d | 420 | set-controller BRIDGE TARGET... set the controllers for BRIDGE\n\ |
1a048029 JP |
421 | get-fail-mode BRIDGE print the fail-mode for BRIDGE\n\ |
422 | del-fail-mode BRIDGE delete the fail-mode for BRIDGE\n\ | |
423 | set-fail-mode BRIDGE MODE set the fail-mode for BRIDGE to MODE\n\ | |
8f7501e8 | 424 | \n\ |
24b8b259 | 425 | Manager commands:\n\ |
a892775d BP |
426 | get-manager print the managers\n\ |
427 | del-manager delete the managers\n\ | |
3ffed5cb | 428 | [--inactivity-probe=MSECS]\n\ |
a892775d | 429 | set-manager TARGET... set the list of managers to TARGET...\n\ |
24b8b259 | 430 | \n\ |
8f7501e8 BP |
431 | SSL commands:\n\ |
432 | get-ssl print the SSL configuration\n\ | |
433 | del-ssl delete the SSL configuration\n\ | |
434 | set-ssl PRIV-KEY CERT CA-CERT set the SSL configuration\n\ | |
435 | \n\ | |
99eef98b DF |
436 | Auto Attach commands:\n\ |
437 | add-aa-mapping BRIDGE I-SID VLAN add Auto Attach mapping to BRIDGE\n\ | |
438 | del-aa-mapping BRIDGE I-SID VLAN delete Auto Attach mapping VLAN from BRIDGE\n\ | |
439 | get-aa-mapping BRIDGE get Auto Attach mappings from BRIDGE\n\ | |
440 | \n\ | |
18ee958b JP |
441 | Switch commands:\n\ |
442 | emer-reset reset switch to known good state\n\ | |
443 | \n\ | |
07ff77cc | 444 | %s\ |
8519ea87 | 445 | %s\ |
8f7501e8 BP |
446 | \n\ |
447 | Options:\n\ | |
448 | --db=DATABASE connect to DATABASE\n\ | |
449 | (default: %s)\n\ | |
ae9a3235 | 450 | --no-wait do not wait for ovs-vswitchd to reconfigure\n\ |
fba6bd1d | 451 | --retry keep trying to connect to server forever\n\ |
ae9a3235 BP |
452 | -t, --timeout=SECS wait at most SECS seconds for ovs-vswitchd\n\ |
453 | --dry-run do not commit changes to database\n\ | |
8f7501e8 | 454 | --oneline print exactly one line of output per command\n", |
8519ea87 MM |
455 | program_name, program_name, ctl_get_db_cmd_usage(), |
456 | ctl_list_db_tables_usage(), ctl_default_db()); | |
bcb58ce0 | 457 | table_usage(); |
c75d1511 | 458 | vlog_usage(); |
ae9a3235 BP |
459 | printf("\ |
460 | --no-syslog equivalent to --verbose=vsctl:syslog:warn\n"); | |
c33fa581 | 461 | stream_usage("database", true, true, true); |
8f7501e8 BP |
462 | printf("\n\ |
463 | Other options:\n\ | |
464 | -h, --help display this help message\n\ | |
465 | -V, --version display version information\n"); | |
c75d1511 BP |
466 | exit(EXIT_SUCCESS); |
467 | } | |
468 | ||
c75d1511 | 469 | \f |
07ff77cc | 470 | /* ovs-vsctl specific context. Inherits the 'struct ctl_context' as base. */ |
5d9cb63c | 471 | struct vsctl_context { |
07ff77cc | 472 | struct ctl_context base; |
f8ff4bc4 BP |
473 | |
474 | /* Modifiable state. */ | |
5d9cb63c | 475 | const struct ovsrec_open_vswitch *ovs; |
f74055e7 | 476 | bool verified_ports; |
87b23a01 | 477 | |
5ce5a6b5 BP |
478 | /* A cache of the contents of the database. |
479 | * | |
480 | * A command that needs to use any of this information must first call | |
481 | * vsctl_context_populate_cache(). A command that changes anything that | |
482 | * could invalidate the cache must either call | |
483 | * vsctl_context_invalidate_cache() or manually update the cache to | |
484 | * maintain its correctness. */ | |
485 | bool cache_valid; | |
486 | struct shash bridges; /* Maps from bridge name to struct vsctl_bridge. */ | |
487 | struct shash ports; /* Maps from port name to struct vsctl_port. */ | |
488 | struct shash ifaces; /* Maps from port name to struct vsctl_iface. */ | |
5d9cb63c BP |
489 | }; |
490 | ||
c75d1511 BP |
491 | struct vsctl_bridge { |
492 | struct ovsrec_bridge *br_cfg; | |
493 | char *name; | |
ca6ba700 | 494 | struct ovs_list ports; /* Contains "struct vsctl_port"s. */ |
5341d046 BP |
495 | |
496 | /* VLAN ("fake") bridge support. | |
497 | * | |
498 | * Use 'parent != NULL' to detect a fake bridge, because 'vlan' can be 0 | |
499 | * in either case. */ | |
a341ee57 BP |
500 | struct hmap children; /* VLAN bridges indexed by 'vlan'. */ |
501 | struct hmap_node children_node; /* Node in parent's 'children' hmap. */ | |
5341d046 BP |
502 | struct vsctl_bridge *parent; /* Real bridge, or NULL. */ |
503 | int vlan; /* VLAN VID (0...4095), or 0. */ | |
c75d1511 BP |
504 | }; |
505 | ||
506 | struct vsctl_port { | |
ca6ba700 TG |
507 | struct ovs_list ports_node; /* In struct vsctl_bridge's 'ports' list. */ |
508 | struct ovs_list ifaces; /* Contains "struct vsctl_iface"s. */ | |
c75d1511 BP |
509 | struct ovsrec_port *port_cfg; |
510 | struct vsctl_bridge *bridge; | |
511 | }; | |
512 | ||
513 | struct vsctl_iface { | |
ca6ba700 | 514 | struct ovs_list ifaces_node; /* In struct vsctl_port's 'ifaces' list. */ |
c75d1511 BP |
515 | struct ovsrec_interface *iface_cfg; |
516 | struct vsctl_port *port; | |
517 | }; | |
518 | ||
ec4eed45 | 519 | /* Casts 'base' into 'struct vsctl_context'. */ |
07ff77cc AW |
520 | static struct vsctl_context * |
521 | vsctl_context_cast(struct ctl_context *base) | |
522 | { | |
523 | return CONTAINER_OF(base, struct vsctl_context, base); | |
524 | } | |
525 | ||
5dd9826c BP |
526 | static struct vsctl_bridge *find_vlan_bridge(struct vsctl_bridge *parent, |
527 | int vlan); | |
528 | ||
bb1c67c8 | 529 | static char * |
07ff77cc | 530 | vsctl_context_to_string(const struct ctl_context *ctx) |
bb1c67c8 BP |
531 | { |
532 | const struct shash_node *node; | |
533 | struct svec words; | |
534 | char *s; | |
535 | int i; | |
536 | ||
537 | svec_init(&words); | |
538 | SHASH_FOR_EACH (node, &ctx->options) { | |
539 | svec_add(&words, node->name); | |
540 | } | |
541 | for (i = 0; i < ctx->argc; i++) { | |
542 | svec_add(&words, ctx->argv[i]); | |
543 | } | |
544 | svec_terminate(&words); | |
545 | ||
546 | s = process_escape_args(words.names); | |
547 | ||
548 | svec_destroy(&words); | |
549 | ||
550 | return s; | |
551 | } | |
552 | ||
f74055e7 | 553 | static void |
07ff77cc | 554 | verify_ports(struct vsctl_context *vsctl_ctx) |
f74055e7 | 555 | { |
07ff77cc | 556 | if (!vsctl_ctx->verified_ports) { |
f74055e7 BP |
557 | const struct ovsrec_bridge *bridge; |
558 | const struct ovsrec_port *port; | |
559 | ||
07ff77cc AW |
560 | ovsrec_open_vswitch_verify_bridges(vsctl_ctx->ovs); |
561 | OVSREC_BRIDGE_FOR_EACH (bridge, vsctl_ctx->base.idl) { | |
f74055e7 BP |
562 | ovsrec_bridge_verify_ports(bridge); |
563 | } | |
07ff77cc | 564 | OVSREC_PORT_FOR_EACH (port, vsctl_ctx->base.idl) { |
f74055e7 BP |
565 | ovsrec_port_verify_interfaces(port); |
566 | } | |
567 | ||
07ff77cc | 568 | vsctl_ctx->verified_ports = true; |
f74055e7 BP |
569 | } |
570 | } | |
571 | ||
c75d1511 | 572 | static struct vsctl_bridge * |
07ff77cc | 573 | add_bridge_to_cache(struct vsctl_context *vsctl_ctx, |
a341ee57 BP |
574 | struct ovsrec_bridge *br_cfg, const char *name, |
575 | struct vsctl_bridge *parent, int vlan) | |
c75d1511 BP |
576 | { |
577 | struct vsctl_bridge *br = xmalloc(sizeof *br); | |
578 | br->br_cfg = br_cfg; | |
579 | br->name = xstrdup(name); | |
417e7e66 | 580 | ovs_list_init(&br->ports); |
c75d1511 BP |
581 | br->parent = parent; |
582 | br->vlan = vlan; | |
a341ee57 BP |
583 | hmap_init(&br->children); |
584 | if (parent) { | |
5dd9826c BP |
585 | struct vsctl_bridge *conflict = find_vlan_bridge(parent, vlan); |
586 | if (conflict) { | |
587 | VLOG_WARN("%s: bridge has multiple VLAN bridges (%s and %s) " | |
588 | "for VLAN %d, but only one is allowed", | |
589 | parent->name, name, conflict->name, vlan); | |
590 | } else { | |
591 | hmap_insert(&parent->children, &br->children_node, | |
592 | hash_int(vlan, 0)); | |
593 | } | |
a341ee57 | 594 | } |
07ff77cc | 595 | shash_add(&vsctl_ctx->bridges, br->name, br); |
c75d1511 BP |
596 | return br; |
597 | } | |
598 | ||
a341ee57 BP |
599 | static void |
600 | ovs_delete_bridge(const struct ovsrec_open_vswitch *ovs, | |
601 | struct ovsrec_bridge *bridge) | |
602 | { | |
603 | struct ovsrec_bridge **bridges; | |
604 | size_t i, n; | |
605 | ||
606 | bridges = xmalloc(sizeof *ovs->bridges * ovs->n_bridges); | |
607 | for (i = n = 0; i < ovs->n_bridges; i++) { | |
608 | if (ovs->bridges[i] != bridge) { | |
609 | bridges[n++] = ovs->bridges[i]; | |
610 | } | |
611 | } | |
612 | ovsrec_open_vswitch_set_bridges(ovs, bridges, n); | |
613 | free(bridges); | |
614 | } | |
615 | ||
616 | static void | |
07ff77cc | 617 | del_cached_bridge(struct vsctl_context *vsctl_ctx, struct vsctl_bridge *br) |
a341ee57 | 618 | { |
417e7e66 | 619 | ovs_assert(ovs_list_is_empty(&br->ports)); |
cb22974d | 620 | ovs_assert(hmap_is_empty(&br->children)); |
a341ee57 BP |
621 | if (br->parent) { |
622 | hmap_remove(&br->parent->children, &br->children_node); | |
623 | } | |
624 | if (br->br_cfg) { | |
625 | ovsrec_bridge_delete(br->br_cfg); | |
07ff77cc | 626 | ovs_delete_bridge(vsctl_ctx->ovs, br->br_cfg); |
a341ee57 | 627 | } |
07ff77cc | 628 | shash_find_and_delete(&vsctl_ctx->bridges, br->name); |
a341ee57 BP |
629 | hmap_destroy(&br->children); |
630 | free(br->name); | |
631 | free(br); | |
632 | } | |
633 | ||
c75d1511 BP |
634 | static bool |
635 | port_is_fake_bridge(const struct ovsrec_port *port_cfg) | |
636 | { | |
637 | return (port_cfg->fake_bridge | |
638 | && port_cfg->tag | |
5341d046 | 639 | && *port_cfg->tag >= 0 && *port_cfg->tag <= 4095); |
c75d1511 BP |
640 | } |
641 | ||
642 | static struct vsctl_bridge * | |
a341ee57 | 643 | find_vlan_bridge(struct vsctl_bridge *parent, int vlan) |
c75d1511 | 644 | { |
a341ee57 | 645 | struct vsctl_bridge *child; |
c75d1511 | 646 | |
a341ee57 BP |
647 | HMAP_FOR_EACH_IN_BUCKET (child, children_node, hash_int(vlan, 0), |
648 | &parent->children) { | |
649 | if (child->vlan == vlan) { | |
650 | return child; | |
c75d1511 BP |
651 | } |
652 | } | |
653 | ||
654 | return NULL; | |
655 | } | |
656 | ||
a341ee57 | 657 | static struct vsctl_port * |
07ff77cc | 658 | add_port_to_cache(struct vsctl_context *vsctl_ctx, struct vsctl_bridge *parent, |
a341ee57 BP |
659 | struct ovsrec_port *port_cfg) |
660 | { | |
661 | struct vsctl_port *port; | |
662 | ||
663 | if (port_cfg->tag | |
664 | && *port_cfg->tag >= 0 && *port_cfg->tag <= 4095) { | |
665 | struct vsctl_bridge *vlan_bridge; | |
666 | ||
667 | vlan_bridge = find_vlan_bridge(parent, *port_cfg->tag); | |
668 | if (vlan_bridge) { | |
669 | parent = vlan_bridge; | |
670 | } | |
671 | } | |
672 | ||
673 | port = xmalloc(sizeof *port); | |
417e7e66 BW |
674 | ovs_list_push_back(&parent->ports, &port->ports_node); |
675 | ovs_list_init(&port->ifaces); | |
a341ee57 BP |
676 | port->port_cfg = port_cfg; |
677 | port->bridge = parent; | |
07ff77cc | 678 | shash_add(&vsctl_ctx->ports, port_cfg->name, port); |
a341ee57 BP |
679 | |
680 | return port; | |
681 | } | |
682 | ||
683 | static void | |
07ff77cc | 684 | del_cached_port(struct vsctl_context *vsctl_ctx, struct vsctl_port *port) |
a341ee57 | 685 | { |
417e7e66 BW |
686 | ovs_assert(ovs_list_is_empty(&port->ifaces)); |
687 | ovs_list_remove(&port->ports_node); | |
07ff77cc | 688 | shash_find_and_delete(&vsctl_ctx->ports, port->port_cfg->name); |
a341ee57 BP |
689 | ovsrec_port_delete(port->port_cfg); |
690 | free(port); | |
691 | } | |
692 | ||
693 | static struct vsctl_iface * | |
07ff77cc | 694 | add_iface_to_cache(struct vsctl_context *vsctl_ctx, struct vsctl_port *parent, |
a341ee57 BP |
695 | struct ovsrec_interface *iface_cfg) |
696 | { | |
697 | struct vsctl_iface *iface; | |
698 | ||
699 | iface = xmalloc(sizeof *iface); | |
417e7e66 | 700 | ovs_list_push_back(&parent->ifaces, &iface->ifaces_node); |
a341ee57 BP |
701 | iface->iface_cfg = iface_cfg; |
702 | iface->port = parent; | |
07ff77cc | 703 | shash_add(&vsctl_ctx->ifaces, iface_cfg->name, iface); |
a341ee57 BP |
704 | |
705 | return iface; | |
706 | } | |
707 | ||
708 | static void | |
07ff77cc | 709 | del_cached_iface(struct vsctl_context *vsctl_ctx, struct vsctl_iface *iface) |
a341ee57 | 710 | { |
417e7e66 | 711 | ovs_list_remove(&iface->ifaces_node); |
07ff77cc | 712 | shash_find_and_delete(&vsctl_ctx->ifaces, iface->iface_cfg->name); |
a341ee57 BP |
713 | ovsrec_interface_delete(iface->iface_cfg); |
714 | free(iface); | |
715 | } | |
716 | ||
c75d1511 | 717 | static void |
07ff77cc | 718 | vsctl_context_invalidate_cache(struct ctl_context *ctx) |
c75d1511 | 719 | { |
07ff77cc | 720 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
c75d1511 BP |
721 | struct shash_node *node; |
722 | ||
07ff77cc | 723 | if (!vsctl_ctx->cache_valid) { |
5ce5a6b5 BP |
724 | return; |
725 | } | |
07ff77cc | 726 | vsctl_ctx->cache_valid = false; |
5ce5a6b5 | 727 | |
07ff77cc | 728 | SHASH_FOR_EACH (node, &vsctl_ctx->bridges) { |
c75d1511 | 729 | struct vsctl_bridge *bridge = node->data; |
a341ee57 | 730 | hmap_destroy(&bridge->children); |
c75d1511 BP |
731 | free(bridge->name); |
732 | free(bridge); | |
733 | } | |
07ff77cc | 734 | shash_destroy(&vsctl_ctx->bridges); |
c75d1511 | 735 | |
07ff77cc AW |
736 | shash_destroy_free_data(&vsctl_ctx->ports); |
737 | shash_destroy_free_data(&vsctl_ctx->ifaces); | |
c75d1511 BP |
738 | } |
739 | ||
e5e12280 | 740 | static void |
07ff77cc | 741 | pre_get_info(struct ctl_context *ctx) |
e5e12280 BP |
742 | { |
743 | ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_bridges); | |
744 | ||
745 | ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_name); | |
746 | ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_controller); | |
747 | ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_fail_mode); | |
748 | ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_ports); | |
749 | ||
750 | ovsdb_idl_add_column(ctx->idl, &ovsrec_port_col_name); | |
751 | ovsdb_idl_add_column(ctx->idl, &ovsrec_port_col_fake_bridge); | |
752 | ovsdb_idl_add_column(ctx->idl, &ovsrec_port_col_tag); | |
753 | ovsdb_idl_add_column(ctx->idl, &ovsrec_port_col_interfaces); | |
754 | ||
755 | ovsdb_idl_add_column(ctx->idl, &ovsrec_interface_col_name); | |
99eef98b | 756 | |
c3ccfe98 | 757 | ovsdb_idl_add_column(ctx->idl, &ovsrec_interface_col_ofport); |
feb38b6d | 758 | ovsdb_idl_add_column(ctx->idl, &ovsrec_interface_col_error); |
e5e12280 BP |
759 | } |
760 | ||
c75d1511 | 761 | static void |
07ff77cc | 762 | vsctl_context_populate_cache(struct ctl_context *ctx) |
c75d1511 | 763 | { |
07ff77cc AW |
764 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
765 | const struct ovsrec_open_vswitch *ovs = vsctl_ctx->ovs; | |
b3c01ed3 | 766 | struct sset bridges, ports; |
c75d1511 BP |
767 | size_t i; |
768 | ||
07ff77cc | 769 | if (vsctl_ctx->cache_valid) { |
5ce5a6b5 BP |
770 | /* Cache is already populated. */ |
771 | return; | |
772 | } | |
07ff77cc AW |
773 | vsctl_ctx->cache_valid = true; |
774 | shash_init(&vsctl_ctx->bridges); | |
775 | shash_init(&vsctl_ctx->ports); | |
776 | shash_init(&vsctl_ctx->ifaces); | |
c75d1511 | 777 | |
b3c01ed3 BP |
778 | sset_init(&bridges); |
779 | sset_init(&ports); | |
c75d1511 BP |
780 | for (i = 0; i < ovs->n_bridges; i++) { |
781 | struct ovsrec_bridge *br_cfg = ovs->bridges[i]; | |
782 | struct vsctl_bridge *br; | |
783 | size_t j; | |
784 | ||
b3c01ed3 | 785 | if (!sset_add(&bridges, br_cfg->name)) { |
c75d1511 BP |
786 | VLOG_WARN("%s: database contains duplicate bridge name", |
787 | br_cfg->name); | |
788 | continue; | |
789 | } | |
07ff77cc | 790 | br = add_bridge_to_cache(vsctl_ctx, br_cfg, br_cfg->name, NULL, 0); |
c75d1511 BP |
791 | |
792 | for (j = 0; j < br_cfg->n_ports; j++) { | |
793 | struct ovsrec_port *port_cfg = br_cfg->ports[j]; | |
794 | ||
b3c01ed3 | 795 | if (!sset_add(&ports, port_cfg->name)) { |
48a69501 | 796 | /* Duplicate port name. (We will warn about that later.) */ |
c75d1511 BP |
797 | continue; |
798 | } | |
799 | ||
800 | if (port_is_fake_bridge(port_cfg) | |
b3c01ed3 | 801 | && sset_add(&bridges, port_cfg->name)) { |
07ff77cc | 802 | add_bridge_to_cache(vsctl_ctx, NULL, port_cfg->name, br, |
a341ee57 | 803 | *port_cfg->tag); |
c75d1511 BP |
804 | } |
805 | } | |
806 | } | |
b3c01ed3 BP |
807 | sset_destroy(&bridges); |
808 | sset_destroy(&ports); | |
c75d1511 | 809 | |
b3c01ed3 | 810 | sset_init(&bridges); |
c75d1511 BP |
811 | for (i = 0; i < ovs->n_bridges; i++) { |
812 | struct ovsrec_bridge *br_cfg = ovs->bridges[i]; | |
813 | struct vsctl_bridge *br; | |
814 | size_t j; | |
815 | ||
b3c01ed3 | 816 | if (!sset_add(&bridges, br_cfg->name)) { |
c75d1511 BP |
817 | continue; |
818 | } | |
07ff77cc | 819 | br = shash_find_data(&vsctl_ctx->bridges, br_cfg->name); |
c75d1511 BP |
820 | for (j = 0; j < br_cfg->n_ports; j++) { |
821 | struct ovsrec_port *port_cfg = br_cfg->ports[j]; | |
822 | struct vsctl_port *port; | |
823 | size_t k; | |
824 | ||
07ff77cc | 825 | port = shash_find_data(&vsctl_ctx->ports, port_cfg->name); |
48a69501 BP |
826 | if (port) { |
827 | if (port_cfg == port->port_cfg) { | |
828 | VLOG_WARN("%s: port is in multiple bridges (%s and %s)", | |
829 | port_cfg->name, br->name, port->bridge->name); | |
830 | } else { | |
831 | /* Log as an error because this violates the database's | |
832 | * uniqueness constraints, so the database server shouldn't | |
833 | * have allowed it. */ | |
834 | VLOG_ERR("%s: database contains duplicate port name", | |
835 | port_cfg->name); | |
836 | } | |
c75d1511 BP |
837 | continue; |
838 | } | |
839 | ||
840 | if (port_is_fake_bridge(port_cfg) | |
b3c01ed3 | 841 | && !sset_add(&bridges, port_cfg->name)) { |
c75d1511 BP |
842 | continue; |
843 | } | |
844 | ||
07ff77cc | 845 | port = add_port_to_cache(vsctl_ctx, br, port_cfg); |
c75d1511 BP |
846 | for (k = 0; k < port_cfg->n_interfaces; k++) { |
847 | struct ovsrec_interface *iface_cfg = port_cfg->interfaces[k]; | |
848 | struct vsctl_iface *iface; | |
849 | ||
07ff77cc | 850 | iface = shash_find_data(&vsctl_ctx->ifaces, iface_cfg->name); |
48a69501 BP |
851 | if (iface) { |
852 | if (iface_cfg == iface->iface_cfg) { | |
853 | VLOG_WARN("%s: interface is in multiple ports " | |
854 | "(%s and %s)", | |
855 | iface_cfg->name, | |
856 | iface->port->port_cfg->name, | |
857 | port->port_cfg->name); | |
858 | } else { | |
859 | /* Log as an error because this violates the database's | |
860 | * uniqueness constraints, so the database server | |
861 | * shouldn't have allowed it. */ | |
862 | VLOG_ERR("%s: database contains duplicate interface " | |
863 | "name", iface_cfg->name); | |
864 | } | |
c75d1511 BP |
865 | continue; |
866 | } | |
867 | ||
07ff77cc | 868 | add_iface_to_cache(vsctl_ctx, port, iface_cfg); |
c75d1511 BP |
869 | } |
870 | } | |
871 | } | |
b3c01ed3 | 872 | sset_destroy(&bridges); |
c75d1511 BP |
873 | } |
874 | ||
875 | static void | |
07ff77cc | 876 | check_conflicts(struct vsctl_context *vsctl_ctx, const char *name, |
c75d1511 BP |
877 | char *msg) |
878 | { | |
879 | struct vsctl_iface *iface; | |
880 | struct vsctl_port *port; | |
881 | ||
07ff77cc | 882 | verify_ports(vsctl_ctx); |
f74055e7 | 883 | |
07ff77cc AW |
884 | if (shash_find(&vsctl_ctx->bridges, name)) { |
885 | ctl_fatal("%s because a bridge named %s already exists", | |
c88b6a27 | 886 | msg, name); |
c75d1511 BP |
887 | } |
888 | ||
07ff77cc | 889 | port = shash_find_data(&vsctl_ctx->ports, name); |
c75d1511 | 890 | if (port) { |
07ff77cc | 891 | ctl_fatal("%s because a port named %s already exists on " |
c88b6a27 | 892 | "bridge %s", msg, name, port->bridge->name); |
c75d1511 BP |
893 | } |
894 | ||
07ff77cc | 895 | iface = shash_find_data(&vsctl_ctx->ifaces, name); |
c75d1511 | 896 | if (iface) { |
07ff77cc | 897 | ctl_fatal("%s because an interface named %s already exists " |
c88b6a27 | 898 | "on bridge %s", msg, name, iface->port->bridge->name); |
c75d1511 BP |
899 | } |
900 | ||
901 | free(msg); | |
902 | } | |
903 | ||
904 | static struct vsctl_bridge * | |
07ff77cc | 905 | find_bridge(struct vsctl_context *vsctl_ctx, const char *name, bool must_exist) |
c75d1511 | 906 | { |
5ce5a6b5 BP |
907 | struct vsctl_bridge *br; |
908 | ||
07ff77cc | 909 | ovs_assert(vsctl_ctx->cache_valid); |
5ce5a6b5 | 910 | |
07ff77cc | 911 | br = shash_find_data(&vsctl_ctx->bridges, name); |
01845ce8 | 912 | if (must_exist && !br) { |
07ff77cc | 913 | ctl_fatal("no bridge named %s", name); |
c75d1511 | 914 | } |
07ff77cc | 915 | ovsrec_open_vswitch_verify_bridges(vsctl_ctx->ovs); |
c75d1511 BP |
916 | return br; |
917 | } | |
918 | ||
975ac531 | 919 | static struct vsctl_bridge * |
07ff77cc AW |
920 | find_real_bridge(struct vsctl_context *vsctl_ctx, |
921 | const char *name, bool must_exist) | |
975ac531 | 922 | { |
07ff77cc | 923 | struct vsctl_bridge *br = find_bridge(vsctl_ctx, name, must_exist); |
975ac531 | 924 | if (br && br->parent) { |
07ff77cc | 925 | ctl_fatal("%s is a fake bridge", name); |
975ac531 JP |
926 | } |
927 | return br; | |
928 | } | |
929 | ||
c75d1511 | 930 | static struct vsctl_port * |
07ff77cc | 931 | find_port(struct vsctl_context *vsctl_ctx, const char *name, bool must_exist) |
c75d1511 | 932 | { |
5ce5a6b5 BP |
933 | struct vsctl_port *port; |
934 | ||
07ff77cc | 935 | ovs_assert(vsctl_ctx->cache_valid); |
5ce5a6b5 | 936 | |
07ff77cc | 937 | port = shash_find_data(&vsctl_ctx->ports, name); |
460aad80 | 938 | if (port && !strcmp(name, port->bridge->name)) { |
01845ce8 BP |
939 | port = NULL; |
940 | } | |
941 | if (must_exist && !port) { | |
07ff77cc | 942 | ctl_fatal("no port named %s", name); |
c75d1511 | 943 | } |
07ff77cc | 944 | verify_ports(vsctl_ctx); |
c75d1511 BP |
945 | return port; |
946 | } | |
947 | ||
948 | static struct vsctl_iface * | |
07ff77cc | 949 | find_iface(struct vsctl_context *vsctl_ctx, const char *name, bool must_exist) |
c75d1511 | 950 | { |
5ce5a6b5 BP |
951 | struct vsctl_iface *iface; |
952 | ||
07ff77cc | 953 | ovs_assert(vsctl_ctx->cache_valid); |
5ce5a6b5 | 954 | |
07ff77cc | 955 | iface = shash_find_data(&vsctl_ctx->ifaces, name); |
460aad80 | 956 | if (iface && !strcmp(name, iface->port->bridge->name)) { |
01845ce8 BP |
957 | iface = NULL; |
958 | } | |
959 | if (must_exist && !iface) { | |
07ff77cc | 960 | ctl_fatal("no interface named %s", name); |
c75d1511 | 961 | } |
07ff77cc | 962 | verify_ports(vsctl_ctx); |
c75d1511 BP |
963 | return iface; |
964 | } | |
965 | ||
966 | static void | |
967 | bridge_insert_port(struct ovsrec_bridge *br, struct ovsrec_port *port) | |
968 | { | |
969 | struct ovsrec_port **ports; | |
970 | size_t i; | |
971 | ||
972 | ports = xmalloc(sizeof *br->ports * (br->n_ports + 1)); | |
973 | for (i = 0; i < br->n_ports; i++) { | |
974 | ports[i] = br->ports[i]; | |
975 | } | |
c75d1511 BP |
976 | ports[br->n_ports] = port; |
977 | ovsrec_bridge_set_ports(br, ports, br->n_ports + 1); | |
978 | free(ports); | |
979 | } | |
980 | ||
981 | static void | |
982 | bridge_delete_port(struct ovsrec_bridge *br, struct ovsrec_port *port) | |
983 | { | |
984 | struct ovsrec_port **ports; | |
985 | size_t i, n; | |
986 | ||
987 | ports = xmalloc(sizeof *br->ports * br->n_ports); | |
988 | for (i = n = 0; i < br->n_ports; i++) { | |
989 | if (br->ports[i] != port) { | |
990 | ports[n++] = br->ports[i]; | |
991 | } | |
992 | } | |
993 | ovsrec_bridge_set_ports(br, ports, n); | |
994 | free(ports); | |
995 | } | |
996 | ||
997 | static void | |
998 | ovs_insert_bridge(const struct ovsrec_open_vswitch *ovs, | |
999 | struct ovsrec_bridge *bridge) | |
1000 | { | |
1001 | struct ovsrec_bridge **bridges; | |
1002 | size_t i; | |
1003 | ||
1004 | bridges = xmalloc(sizeof *ovs->bridges * (ovs->n_bridges + 1)); | |
1005 | for (i = 0; i < ovs->n_bridges; i++) { | |
1006 | bridges[i] = ovs->bridges[i]; | |
1007 | } | |
1008 | bridges[ovs->n_bridges] = bridge; | |
1009 | ovsrec_open_vswitch_set_bridges(ovs, bridges, ovs->n_bridges + 1); | |
1010 | free(bridges); | |
1011 | } | |
1012 | ||
524555d1 | 1013 | static void |
07ff77cc | 1014 | cmd_init(struct ctl_context *ctx OVS_UNUSED) |
524555d1 BP |
1015 | { |
1016 | } | |
1017 | ||
d33340a5 | 1018 | static struct cmd_show_table cmd_show_tables[] = { |
9b1735a7 BP |
1019 | {&ovsrec_table_open_vswitch, |
1020 | NULL, | |
1021 | {&ovsrec_open_vswitch_col_manager_options, | |
1022 | &ovsrec_open_vswitch_col_bridges, | |
016e4684 AW |
1023 | &ovsrec_open_vswitch_col_ovs_version}, |
1024 | {NULL, NULL, NULL} | |
6530be3b | 1025 | }, |
9b1735a7 BP |
1026 | |
1027 | {&ovsrec_table_bridge, | |
1028 | &ovsrec_bridge_col_name, | |
1029 | {&ovsrec_bridge_col_controller, | |
1030 | &ovsrec_bridge_col_fail_mode, | |
6ca88964 | 1031 | &ovsrec_bridge_col_datapath_type, |
016e4684 AW |
1032 | &ovsrec_bridge_col_ports}, |
1033 | {NULL, NULL, NULL} | |
6530be3b | 1034 | }, |
9b1735a7 BP |
1035 | |
1036 | {&ovsrec_table_port, | |
1037 | &ovsrec_port_col_name, | |
1038 | {&ovsrec_port_col_tag, | |
1039 | &ovsrec_port_col_trunks, | |
016e4684 AW |
1040 | &ovsrec_port_col_interfaces}, |
1041 | {NULL, NULL, NULL} | |
6530be3b | 1042 | }, |
9b1735a7 BP |
1043 | |
1044 | {&ovsrec_table_interface, | |
1045 | &ovsrec_interface_col_name, | |
1046 | {&ovsrec_interface_col_type, | |
1047 | &ovsrec_interface_col_options, | |
771c8ea0 MAA |
1048 | &ovsrec_interface_col_error, |
1049 | &ovsrec_interface_col_bfd_status}, | |
016e4684 | 1050 | {NULL, NULL, NULL} |
6530be3b | 1051 | }, |
9b1735a7 BP |
1052 | |
1053 | {&ovsrec_table_controller, | |
1054 | &ovsrec_controller_col_target, | |
1055 | {&ovsrec_controller_col_is_connected, | |
1056 | NULL, | |
016e4684 AW |
1057 | NULL}, |
1058 | {NULL, NULL, NULL} | |
6530be3b | 1059 | }, |
9b1735a7 BP |
1060 | |
1061 | {&ovsrec_table_manager, | |
1062 | &ovsrec_manager_col_target, | |
1063 | {&ovsrec_manager_col_is_connected, | |
1064 | NULL, | |
016e4684 AW |
1065 | NULL}, |
1066 | {NULL, NULL, NULL} | |
6530be3b | 1067 | }, |
9b1735a7 | 1068 | |
016e4684 | 1069 | {NULL, NULL, {NULL, NULL, NULL}, {NULL, NULL, NULL}} |
af046a16 | 1070 | }; |
9b1735a7 | 1071 | |
e5e12280 | 1072 | static void |
07ff77cc | 1073 | pre_cmd_emer_reset(struct ctl_context *ctx) |
e5e12280 | 1074 | { |
87824b0b | 1075 | ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_manager_options); |
e5e12280 BP |
1076 | ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_ssl); |
1077 | ||
1078 | ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_controller); | |
f67e3b66 | 1079 | ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_fail_mode); |
e5e12280 BP |
1080 | ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_mirrors); |
1081 | ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_netflow); | |
1082 | ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_sflow); | |
29089a54 | 1083 | ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_ipfix); |
e5e12280 BP |
1084 | ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_flood_vlans); |
1085 | ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_other_config); | |
1086 | ||
1087 | ovsdb_idl_add_column(ctx->idl, &ovsrec_port_col_other_config); | |
1088 | ||
1089 | ovsdb_idl_add_column(ctx->idl, | |
1090 | &ovsrec_interface_col_ingress_policing_rate); | |
1091 | ovsdb_idl_add_column(ctx->idl, | |
1092 | &ovsrec_interface_col_ingress_policing_burst); | |
1093 | } | |
1094 | ||
18ee958b | 1095 | static void |
07ff77cc | 1096 | cmd_emer_reset(struct ctl_context *ctx) |
18ee958b | 1097 | { |
07ff77cc | 1098 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
18ee958b JP |
1099 | const struct ovsdb_idl *idl = ctx->idl; |
1100 | const struct ovsrec_bridge *br; | |
1101 | const struct ovsrec_port *port; | |
1102 | const struct ovsrec_interface *iface; | |
28a14bf3 EJ |
1103 | const struct ovsrec_mirror *mirror, *next_mirror; |
1104 | const struct ovsrec_controller *ctrl, *next_ctrl; | |
1105 | const struct ovsrec_manager *mgr, *next_mgr; | |
1106 | const struct ovsrec_netflow *nf, *next_nf; | |
1107 | const struct ovsrec_ssl *ssl, *next_ssl; | |
1108 | const struct ovsrec_sflow *sflow, *next_sflow; | |
29089a54 RL |
1109 | const struct ovsrec_ipfix *ipfix, *next_ipfix; |
1110 | const struct ovsrec_flow_sample_collector_set *fscset, *next_fscset; | |
18ee958b | 1111 | |
18ee958b | 1112 | /* Reset the Open_vSwitch table. */ |
07ff77cc AW |
1113 | ovsrec_open_vswitch_set_manager_options(vsctl_ctx->ovs, NULL, 0); |
1114 | ovsrec_open_vswitch_set_ssl(vsctl_ctx->ovs, NULL); | |
18ee958b JP |
1115 | |
1116 | OVSREC_BRIDGE_FOR_EACH (br, idl) { | |
a699f614 | 1117 | const char *hwaddr; |
18ee958b JP |
1118 | |
1119 | ovsrec_bridge_set_controller(br, NULL, 0); | |
f67e3b66 | 1120 | ovsrec_bridge_set_fail_mode(br, NULL); |
18ee958b JP |
1121 | ovsrec_bridge_set_mirrors(br, NULL, 0); |
1122 | ovsrec_bridge_set_netflow(br, NULL); | |
1123 | ovsrec_bridge_set_sflow(br, NULL); | |
29089a54 | 1124 | ovsrec_bridge_set_ipfix(br, NULL); |
18ee958b JP |
1125 | ovsrec_bridge_set_flood_vlans(br, NULL, 0); |
1126 | ||
1127 | /* We only want to save the "hwaddr" key from other_config. */ | |
a699f614 EJ |
1128 | hwaddr = smap_get(&br->other_config, "hwaddr"); |
1129 | if (hwaddr) { | |
aaf881c6 | 1130 | const struct smap smap = SMAP_CONST1(&smap, "hwaddr", hwaddr); |
a699f614 | 1131 | ovsrec_bridge_set_other_config(br, &smap); |
18ee958b | 1132 | } else { |
a699f614 | 1133 | ovsrec_bridge_set_other_config(br, NULL); |
18ee958b JP |
1134 | } |
1135 | } | |
1136 | ||
1137 | OVSREC_PORT_FOR_EACH (port, idl) { | |
a699f614 | 1138 | ovsrec_port_set_other_config(port, NULL); |
18ee958b JP |
1139 | } |
1140 | ||
1141 | OVSREC_INTERFACE_FOR_EACH (iface, idl) { | |
1142 | /* xxx What do we do about gre/patch devices created by mgr? */ | |
1143 | ||
1144 | ovsrec_interface_set_ingress_policing_rate(iface, 0); | |
1145 | ovsrec_interface_set_ingress_policing_burst(iface, 0); | |
1146 | } | |
28a14bf3 EJ |
1147 | |
1148 | OVSREC_MIRROR_FOR_EACH_SAFE (mirror, next_mirror, idl) { | |
1149 | ovsrec_mirror_delete(mirror); | |
1150 | } | |
1151 | ||
1152 | OVSREC_CONTROLLER_FOR_EACH_SAFE (ctrl, next_ctrl, idl) { | |
1153 | ovsrec_controller_delete(ctrl); | |
1154 | } | |
1155 | ||
1156 | OVSREC_MANAGER_FOR_EACH_SAFE (mgr, next_mgr, idl) { | |
1157 | ovsrec_manager_delete(mgr); | |
1158 | } | |
1159 | ||
1160 | OVSREC_NETFLOW_FOR_EACH_SAFE (nf, next_nf, idl) { | |
1161 | ovsrec_netflow_delete(nf); | |
1162 | } | |
1163 | ||
1164 | OVSREC_SSL_FOR_EACH_SAFE (ssl, next_ssl, idl) { | |
1165 | ovsrec_ssl_delete(ssl); | |
1166 | } | |
1167 | ||
1168 | OVSREC_SFLOW_FOR_EACH_SAFE (sflow, next_sflow, idl) { | |
1169 | ovsrec_sflow_delete(sflow); | |
1170 | } | |
5ce5a6b5 | 1171 | |
29089a54 RL |
1172 | OVSREC_IPFIX_FOR_EACH_SAFE (ipfix, next_ipfix, idl) { |
1173 | ovsrec_ipfix_delete(ipfix); | |
1174 | } | |
1175 | ||
1176 | OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH_SAFE (fscset, next_fscset, idl) { | |
1177 | ovsrec_flow_sample_collector_set_delete(fscset); | |
1178 | } | |
1179 | ||
5ce5a6b5 | 1180 | vsctl_context_invalidate_cache(ctx); |
18ee958b JP |
1181 | } |
1182 | ||
45339539 WT |
1183 | static struct ovsrec_datapath * |
1184 | find_datapath(struct vsctl_context *vsctl_ctx, const char *dp_name) | |
1185 | { | |
1186 | const struct ovsrec_open_vswitch *ovs = vsctl_ctx->ovs; | |
1187 | ||
1188 | for (int i = 0; i < ovs->n_datapaths; i++) { | |
1189 | if (!strcmp(ovs->key_datapaths[i], dp_name)) { | |
1190 | return ovs->value_datapaths[i]; | |
1191 | } | |
1192 | } | |
1193 | return NULL; | |
1194 | } | |
1195 | ||
1196 | static struct ovsrec_ct_zone * | |
1197 | find_ct_zone(struct ovsrec_datapath *dp, const int64_t zone_id) | |
1198 | { | |
1199 | for (int i = 0; i < dp->n_ct_zones; i++) { | |
1200 | if (dp->key_ct_zones[i] == zone_id) { | |
1201 | return dp->value_ct_zones[i]; | |
1202 | } | |
1203 | } | |
1204 | return NULL; | |
1205 | } | |
1206 | ||
1207 | static struct ovsrec_ct_timeout_policy * | |
1208 | create_timeout_policy(struct ctl_context *ctx, char **tps, int n_tps) | |
1209 | { | |
1210 | const struct ovsrec_ct_timeout_policy_table *tp_table; | |
1211 | const struct ovsrec_ct_timeout_policy *row; | |
1212 | struct ovsrec_ct_timeout_policy *tp = NULL; | |
1213 | struct simap new_tp = SIMAP_INITIALIZER(&new_tp); | |
1214 | ||
1215 | char **policies = xzalloc(sizeof *policies * n_tps); | |
1216 | const char **key_timeouts = xmalloc(sizeof *key_timeouts * n_tps); | |
1217 | int64_t *value_timeouts = xmalloc(sizeof *value_timeouts * n_tps); | |
1218 | ||
1219 | /* Parse timeout arguments. */ | |
1220 | for (int i = 0; i < n_tps; i++) { | |
1221 | policies[i] = xstrdup(tps[i]); | |
1222 | ||
1223 | char *key, *value; | |
1224 | char *policy = policies[i]; | |
1225 | if (!ofputil_parse_key_value(&policy, &key, &value)) { | |
1226 | goto done; | |
1227 | } | |
1228 | key_timeouts[i] = key; | |
1229 | value_timeouts[i] = atoi(value); | |
1230 | simap_put(&new_tp, key, (unsigned int)value_timeouts[i]); | |
1231 | } | |
1232 | ||
1233 | done: | |
1234 | tp_table = ovsrec_ct_timeout_policy_table_get(ctx->idl); | |
1235 | OVSREC_CT_TIMEOUT_POLICY_TABLE_FOR_EACH (row, tp_table) { | |
1236 | struct simap s = SIMAP_INITIALIZER(&s); | |
1237 | ||
1238 | /* Convert to simap. */ | |
1239 | for (int i = 0; i < row->n_timeouts; i++) { | |
1240 | simap_put(&s, row->key_timeouts[i], row->value_timeouts[i]); | |
1241 | } | |
1242 | ||
1243 | if (simap_equal(&s, &new_tp)) { | |
1244 | tp = CONST_CAST(struct ovsrec_ct_timeout_policy *, row); | |
1245 | simap_destroy(&s); | |
1246 | break; | |
1247 | } | |
1248 | simap_destroy(&s); | |
1249 | } | |
1250 | ||
1251 | if (!tp) { | |
1252 | tp = ovsrec_ct_timeout_policy_insert(ctx->txn); | |
1253 | ovsrec_ct_timeout_policy_set_timeouts(tp, key_timeouts, | |
1254 | (const int64_t *)value_timeouts, | |
1255 | n_tps); | |
1256 | } | |
1257 | ||
1258 | for (int i = 0; i < n_tps; i++) { | |
1259 | free(policies[i]); | |
1260 | } | |
1261 | free(policies); | |
1262 | simap_destroy(&new_tp); | |
1263 | free(key_timeouts); | |
1264 | free(value_timeouts); | |
1265 | return tp; | |
1266 | } | |
1267 | ||
1268 | static void | |
1269 | cmd_add_zone_tp(struct ctl_context *ctx) | |
1270 | { | |
1271 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); | |
1272 | struct ovsrec_ct_timeout_policy *tp; | |
1273 | int64_t zone_id; | |
1274 | ||
1275 | const char *dp_name = ctx->argv[1]; | |
1276 | ovs_scan(ctx->argv[2], "zone=%"SCNi64, &zone_id); | |
1277 | bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; | |
1278 | ||
1279 | struct ovsrec_datapath *dp = find_datapath(vsctl_ctx, dp_name); | |
1280 | if (!dp) { | |
1281 | ctl_fatal("datapath %s does not exist", dp_name); | |
1282 | } | |
1283 | ||
1284 | int n_tps = ctx->argc - 3; | |
1285 | struct ovsrec_ct_zone *zone = find_ct_zone(dp, zone_id); | |
1286 | ||
1287 | if (n_tps <= 0) { | |
1288 | ctl_fatal("No timeout policy"); | |
1289 | } | |
1290 | ||
1291 | if (zone && !may_exist) { | |
1292 | ctl_fatal("zone id %"PRIu64" already exists", zone_id); | |
1293 | } | |
1294 | ||
1295 | tp = create_timeout_policy(ctx, &ctx->argv[3], n_tps); | |
1296 | if (zone) { | |
1297 | ovsrec_ct_zone_set_timeout_policy(zone, tp); | |
1298 | } else { | |
1299 | zone = ovsrec_ct_zone_insert(ctx->txn); | |
1300 | ovsrec_ct_zone_set_timeout_policy(zone, tp); | |
1301 | ovsrec_datapath_update_ct_zones_setkey(dp, zone_id, zone); | |
1302 | } | |
1303 | } | |
1304 | ||
1305 | static void | |
1306 | cmd_del_zone_tp(struct ctl_context *ctx) | |
1307 | { | |
1308 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); | |
1309 | int64_t zone_id; | |
1310 | ||
1311 | bool must_exist = !shash_find(&ctx->options, "--if-exists"); | |
1312 | const char *dp_name = ctx->argv[1]; | |
1313 | ovs_scan(ctx->argv[2], "zone=%"SCNi64, &zone_id); | |
1314 | ||
1315 | struct ovsrec_datapath *dp = find_datapath(vsctl_ctx, dp_name); | |
1316 | if (!dp) { | |
1317 | ctl_fatal("datapath %s does not exist", dp_name); | |
1318 | } | |
1319 | ||
1320 | struct ovsrec_ct_zone *zone = find_ct_zone(dp, zone_id); | |
1321 | if (must_exist && !zone) { | |
1322 | ctl_fatal("zone id %"PRIu64" does not exist", zone_id); | |
1323 | } | |
1324 | ||
1325 | if (zone) { | |
1326 | ovsrec_datapath_update_ct_zones_delkey(dp, zone_id); | |
1327 | } | |
1328 | } | |
1329 | ||
1330 | static void | |
1331 | cmd_list_zone_tp(struct ctl_context *ctx) | |
1332 | { | |
1333 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); | |
1334 | ||
1335 | struct ovsrec_datapath *dp = find_datapath(vsctl_ctx, ctx->argv[1]); | |
1336 | if (!dp) { | |
1337 | ctl_fatal("datapath: %s record not found", ctx->argv[1]); | |
1338 | } | |
1339 | ||
1340 | for (int i = 0; i < dp->n_ct_zones; i++) { | |
1341 | struct ovsrec_ct_zone *zone = dp->value_ct_zones[i]; | |
1342 | ds_put_format(&ctx->output, "Zone:%"PRIu64", Timeout Policies: ", | |
1343 | dp->key_ct_zones[i]); | |
1344 | ||
1345 | struct ovsrec_ct_timeout_policy *tp = zone->timeout_policy; | |
1346 | ||
98670b77 YHW |
1347 | if (tp) { |
1348 | for (int j = 0; j < tp->n_timeouts; j++) { | |
1349 | ds_put_format(&ctx->output, "%s=%"PRIu64" ", | |
1350 | tp->key_timeouts[j], tp->value_timeouts[j]); | |
1351 | } | |
1352 | } else { | |
1353 | ds_put_cstr(&ctx->output, "system default"); | |
45339539 WT |
1354 | } |
1355 | ds_chomp(&ctx->output, ' '); | |
1356 | ds_put_char(&ctx->output, '\n'); | |
1357 | } | |
1358 | } | |
1359 | ||
1360 | static void | |
1361 | pre_get_zone(struct ctl_context *ctx) | |
1362 | { | |
1363 | ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_datapaths); | |
1364 | ovsdb_idl_add_column(ctx->idl, &ovsrec_datapath_col_ct_zones); | |
1365 | ovsdb_idl_add_column(ctx->idl, &ovsrec_ct_zone_col_timeout_policy); | |
1366 | ovsdb_idl_add_column(ctx->idl, &ovsrec_ct_timeout_policy_col_timeouts); | |
1367 | } | |
1368 | ||
27501802 WT |
1369 | static void |
1370 | pre_get_dp_cap(struct ctl_context *ctx) | |
1371 | { | |
1372 | ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_datapaths); | |
1373 | ovsdb_idl_add_column(ctx->idl, &ovsrec_datapath_col_capabilities); | |
1374 | } | |
1375 | ||
1376 | static void | |
1377 | cmd_list_dp_cap(struct ctl_context *ctx) | |
1378 | { | |
1379 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); | |
1380 | struct smap_node *node; | |
1381 | ||
1382 | struct ovsrec_datapath *dp = find_datapath(vsctl_ctx, ctx->argv[1]); | |
1383 | if (!dp) { | |
1384 | ctl_fatal("datapath \"%s\" record not found", ctx->argv[1]); | |
1385 | } | |
1386 | ||
1387 | SMAP_FOR_EACH (node, &dp->capabilities) { | |
1388 | ds_put_format(&ctx->output, "%s=%s ",node->key, node->value); | |
1389 | } | |
1390 | ds_chomp(&ctx->output, ' '); | |
1391 | ds_put_char(&ctx->output, '\n'); | |
1392 | } | |
1393 | ||
c75d1511 | 1394 | static void |
07ff77cc | 1395 | cmd_add_br(struct ctl_context *ctx) |
c75d1511 | 1396 | { |
07ff77cc | 1397 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
e3c17733 | 1398 | bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; |
b89d8339 | 1399 | const char *br_name, *parent_name; |
c3ccfe98 | 1400 | struct ovsrec_interface *iface; |
b89d8339 | 1401 | int vlan; |
c75d1511 | 1402 | |
aeee85aa | 1403 | br_name = ctx->argv[1]; |
f75612a1 BP |
1404 | if (!br_name[0]) { |
1405 | ctl_fatal("bridge name must not be empty string"); | |
1406 | } | |
aeee85aa BP |
1407 | if (ctx->argc == 2) { |
1408 | parent_name = NULL; | |
1409 | vlan = 0; | |
1410 | } else if (ctx->argc == 4) { | |
1411 | parent_name = ctx->argv[2]; | |
1412 | vlan = atoi(ctx->argv[3]); | |
5341d046 | 1413 | if (vlan < 0 || vlan > 4095) { |
07ff77cc | 1414 | ctl_fatal("%s: vlan must be between 0 and 4095", ctx->argv[0]); |
aeee85aa BP |
1415 | } |
1416 | } else { | |
07ff77cc | 1417 | ctl_fatal("'%s' command takes exactly 1 or 3 arguments", |
aeee85aa BP |
1418 | ctx->argv[0]); |
1419 | } | |
1420 | ||
5ce5a6b5 | 1421 | vsctl_context_populate_cache(ctx); |
aeee85aa BP |
1422 | if (may_exist) { |
1423 | struct vsctl_bridge *br; | |
1424 | ||
07ff77cc | 1425 | br = find_bridge(vsctl_ctx, br_name, false); |
aeee85aa BP |
1426 | if (br) { |
1427 | if (!parent_name) { | |
1428 | if (br->parent) { | |
07ff77cc | 1429 | ctl_fatal("\"--may-exist add-br %s\" but %s is " |
aeee85aa BP |
1430 | "a VLAN bridge for VLAN %d", |
1431 | br_name, br_name, br->vlan); | |
1432 | } | |
1433 | } else { | |
1434 | if (!br->parent) { | |
07ff77cc | 1435 | ctl_fatal("\"--may-exist add-br %s %s %d\" but %s " |
aeee85aa BP |
1436 | "is not a VLAN bridge", |
1437 | br_name, parent_name, vlan, br_name); | |
1438 | } else if (strcmp(br->parent->name, parent_name)) { | |
07ff77cc | 1439 | ctl_fatal("\"--may-exist add-br %s %s %d\" but %s " |
aeee85aa BP |
1440 | "has the wrong parent %s", |
1441 | br_name, parent_name, vlan, | |
1442 | br_name, br->parent->name); | |
1443 | } else if (br->vlan != vlan) { | |
07ff77cc | 1444 | ctl_fatal("\"--may-exist add-br %s %s %d\" but %s " |
aeee85aa BP |
1445 | "is a VLAN bridge for the wrong VLAN %d", |
1446 | br_name, parent_name, vlan, br_name, br->vlan); | |
1447 | } | |
1448 | } | |
1449 | return; | |
1450 | } | |
1451 | } | |
07ff77cc | 1452 | check_conflicts(vsctl_ctx, br_name, |
c75d1511 BP |
1453 | xasprintf("cannot create a bridge named %s", br_name)); |
1454 | ||
aeee85aa | 1455 | if (!parent_name) { |
c75d1511 | 1456 | struct ovsrec_port *port; |
aeee85aa | 1457 | struct ovsrec_bridge *br; |
c75d1511 | 1458 | |
f8ff4bc4 | 1459 | iface = ovsrec_interface_insert(ctx->txn); |
c75d1511 | 1460 | ovsrec_interface_set_name(iface, br_name); |
9106d88c | 1461 | ovsrec_interface_set_type(iface, "internal"); |
c75d1511 | 1462 | |
f8ff4bc4 | 1463 | port = ovsrec_port_insert(ctx->txn); |
c75d1511 BP |
1464 | ovsrec_port_set_name(port, br_name); |
1465 | ovsrec_port_set_interfaces(port, &iface, 1); | |
1466 | ||
f8ff4bc4 | 1467 | br = ovsrec_bridge_insert(ctx->txn); |
c75d1511 BP |
1468 | ovsrec_bridge_set_name(br, br_name); |
1469 | ovsrec_bridge_set_ports(br, &port, 1); | |
1470 | ||
07ff77cc | 1471 | ovs_insert_bridge(vsctl_ctx->ovs, br); |
aeee85aa | 1472 | } else { |
5dd9826c | 1473 | struct vsctl_bridge *conflict; |
c75d1511 BP |
1474 | struct vsctl_bridge *parent; |
1475 | struct ovsrec_port *port; | |
aeee85aa | 1476 | struct ovsrec_bridge *br; |
c75d1511 BP |
1477 | int64_t tag = vlan; |
1478 | ||
07ff77cc | 1479 | parent = find_bridge(vsctl_ctx, parent_name, false); |
5341d046 | 1480 | if (parent && parent->parent) { |
07ff77cc | 1481 | ctl_fatal("cannot create bridge with fake bridge as parent"); |
c75d1511 BP |
1482 | } |
1483 | if (!parent) { | |
07ff77cc | 1484 | ctl_fatal("parent bridge %s does not exist", parent_name); |
c75d1511 | 1485 | } |
5dd9826c BP |
1486 | conflict = find_vlan_bridge(parent, vlan); |
1487 | if (conflict) { | |
07ff77cc | 1488 | ctl_fatal("bridge %s already has a child VLAN bridge %s " |
5dd9826c BP |
1489 | "on VLAN %d", parent_name, conflict->name, vlan); |
1490 | } | |
c75d1511 BP |
1491 | br = parent->br_cfg; |
1492 | ||
f8ff4bc4 | 1493 | iface = ovsrec_interface_insert(ctx->txn); |
c75d1511 BP |
1494 | ovsrec_interface_set_name(iface, br_name); |
1495 | ovsrec_interface_set_type(iface, "internal"); | |
1496 | ||
f8ff4bc4 | 1497 | port = ovsrec_port_insert(ctx->txn); |
c75d1511 BP |
1498 | ovsrec_port_set_name(port, br_name); |
1499 | ovsrec_port_set_interfaces(port, &iface, 1); | |
1500 | ovsrec_port_set_fake_bridge(port, true); | |
1501 | ovsrec_port_set_tag(port, &tag, 1); | |
dfbe07ba BP |
1502 | |
1503 | bridge_insert_port(br, port); | |
c75d1511 BP |
1504 | } |
1505 | ||
c3ccfe98 | 1506 | post_db_reload_expect_iface(iface); |
5ce5a6b5 | 1507 | vsctl_context_invalidate_cache(ctx); |
c75d1511 BP |
1508 | } |
1509 | ||
1510 | static void | |
07ff77cc | 1511 | del_port(struct vsctl_context *vsctl_ctx, struct vsctl_port *port) |
c75d1511 | 1512 | { |
a341ee57 | 1513 | struct vsctl_iface *iface, *next_iface; |
28a14bf3 | 1514 | |
c75d1511 BP |
1515 | bridge_delete_port((port->bridge->parent |
1516 | ? port->bridge->parent->br_cfg | |
1517 | : port->bridge->br_cfg), port->port_cfg); | |
a341ee57 BP |
1518 | |
1519 | LIST_FOR_EACH_SAFE (iface, next_iface, ifaces_node, &port->ifaces) { | |
07ff77cc | 1520 | del_cached_iface(vsctl_ctx, iface); |
a341ee57 | 1521 | } |
07ff77cc | 1522 | del_cached_port(vsctl_ctx, port); |
a341ee57 BP |
1523 | } |
1524 | ||
1525 | static void | |
07ff77cc | 1526 | del_bridge(struct vsctl_context *vsctl_ctx, struct vsctl_bridge *br) |
a341ee57 BP |
1527 | { |
1528 | struct vsctl_bridge *child, *next_child; | |
1529 | struct vsctl_port *port, *next_port; | |
29089a54 | 1530 | const struct ovsrec_flow_sample_collector_set *fscset, *next_fscset; |
a341ee57 BP |
1531 | |
1532 | HMAP_FOR_EACH_SAFE (child, next_child, children_node, &br->children) { | |
07ff77cc | 1533 | del_bridge(vsctl_ctx, child); |
a341ee57 BP |
1534 | } |
1535 | ||
1536 | LIST_FOR_EACH_SAFE (port, next_port, ports_node, &br->ports) { | |
07ff77cc | 1537 | del_port(vsctl_ctx, port); |
a341ee57 BP |
1538 | } |
1539 | ||
29089a54 | 1540 | OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH_SAFE (fscset, next_fscset, |
07ff77cc | 1541 | vsctl_ctx->base.idl) { |
29089a54 RL |
1542 | if (fscset->bridge == br->br_cfg) { |
1543 | ovsrec_flow_sample_collector_set_delete(fscset); | |
1544 | } | |
1545 | } | |
1546 | ||
07ff77cc | 1547 | del_cached_bridge(vsctl_ctx, br); |
c75d1511 BP |
1548 | } |
1549 | ||
1550 | static void | |
07ff77cc | 1551 | cmd_del_br(struct ctl_context *ctx) |
c75d1511 | 1552 | { |
07ff77cc | 1553 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
460aad80 | 1554 | bool must_exist = !shash_find(&ctx->options, "--if-exists"); |
c75d1511 BP |
1555 | struct vsctl_bridge *bridge; |
1556 | ||
5ce5a6b5 | 1557 | vsctl_context_populate_cache(ctx); |
07ff77cc | 1558 | bridge = find_bridge(vsctl_ctx, ctx->argv[1], must_exist); |
460aad80 | 1559 | if (bridge) { |
07ff77cc | 1560 | del_bridge(vsctl_ctx, bridge); |
c75d1511 | 1561 | } |
c75d1511 BP |
1562 | } |
1563 | ||
dfbe07ba BP |
1564 | static void |
1565 | output_sorted(struct svec *svec, struct ds *output) | |
1566 | { | |
1567 | const char *name; | |
1568 | size_t i; | |
1569 | ||
1570 | svec_sort(svec); | |
1571 | SVEC_FOR_EACH (i, name, svec) { | |
1572 | ds_put_format(output, "%s\n", name); | |
1573 | } | |
1574 | } | |
1575 | ||
c75d1511 | 1576 | static void |
07ff77cc | 1577 | cmd_list_br(struct ctl_context *ctx) |
c75d1511 | 1578 | { |
07ff77cc | 1579 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
c75d1511 | 1580 | struct shash_node *node; |
dfbe07ba | 1581 | struct svec bridges; |
515d830a JP |
1582 | bool real = shash_find(&ctx->options, "--real"); |
1583 | bool fake = shash_find(&ctx->options, "--fake"); | |
1584 | ||
1585 | /* If neither fake nor real were requested, return both. */ | |
1586 | if (!real && !fake) { | |
1587 | real = fake = true; | |
1588 | } | |
c75d1511 | 1589 | |
5ce5a6b5 | 1590 | vsctl_context_populate_cache(ctx); |
dfbe07ba BP |
1591 | |
1592 | svec_init(&bridges); | |
07ff77cc | 1593 | SHASH_FOR_EACH (node, &vsctl_ctx->bridges) { |
c75d1511 | 1594 | struct vsctl_bridge *br = node->data; |
515d830a JP |
1595 | |
1596 | if (br->parent ? fake : real) { | |
1597 | svec_add(&bridges, br->name); | |
1598 | } | |
c75d1511 | 1599 | } |
5d9cb63c | 1600 | output_sorted(&bridges, &ctx->output); |
dfbe07ba | 1601 | svec_destroy(&bridges); |
c75d1511 BP |
1602 | } |
1603 | ||
1604 | static void | |
07ff77cc | 1605 | cmd_br_exists(struct ctl_context *ctx) |
c75d1511 | 1606 | { |
07ff77cc AW |
1607 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
1608 | ||
5ce5a6b5 | 1609 | vsctl_context_populate_cache(ctx); |
07ff77cc | 1610 | if (!find_bridge(vsctl_ctx, ctx->argv[1], false)) { |
ce6f1d1f | 1611 | vsctl_exit(2); |
c75d1511 | 1612 | } |
c75d1511 BP |
1613 | } |
1614 | ||
457e1eb0 | 1615 | static void |
a699f614 EJ |
1616 | set_external_id(struct smap *old, struct smap *new, |
1617 | char *key, char *value) | |
457e1eb0 | 1618 | { |
a699f614 | 1619 | smap_clone(new, old); |
457e1eb0 | 1620 | |
457e1eb0 | 1621 | if (value) { |
a699f614 EJ |
1622 | smap_replace(new, key, value); |
1623 | } else { | |
1624 | smap_remove(new, key); | |
457e1eb0 | 1625 | } |
457e1eb0 BP |
1626 | } |
1627 | ||
e5e12280 | 1628 | static void |
07ff77cc | 1629 | pre_cmd_br_set_external_id(struct ctl_context *ctx) |
e5e12280 BP |
1630 | { |
1631 | pre_get_info(ctx); | |
1632 | ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_external_ids); | |
1633 | ovsdb_idl_add_column(ctx->idl, &ovsrec_port_col_external_ids); | |
1634 | } | |
1635 | ||
457e1eb0 | 1636 | static void |
07ff77cc | 1637 | cmd_br_set_external_id(struct ctl_context *ctx) |
457e1eb0 | 1638 | { |
07ff77cc | 1639 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
457e1eb0 | 1640 | struct vsctl_bridge *bridge; |
a699f614 | 1641 | struct smap new; |
457e1eb0 | 1642 | |
5ce5a6b5 | 1643 | vsctl_context_populate_cache(ctx); |
07ff77cc | 1644 | bridge = find_bridge(vsctl_ctx, ctx->argv[1], true); |
457e1eb0 | 1645 | if (bridge->br_cfg) { |
a699f614 EJ |
1646 | |
1647 | set_external_id(&bridge->br_cfg->external_ids, &new, ctx->argv[2], | |
1648 | ctx->argc >= 4 ? ctx->argv[3] : NULL); | |
f74055e7 | 1649 | ovsrec_bridge_verify_external_ids(bridge->br_cfg); |
a699f614 | 1650 | ovsrec_bridge_set_external_ids(bridge->br_cfg, &new); |
457e1eb0 | 1651 | } else { |
5d9cb63c | 1652 | char *key = xasprintf("fake-bridge-%s", ctx->argv[2]); |
07ff77cc AW |
1653 | struct vsctl_port *port = shash_find_data(&vsctl_ctx->ports, |
1654 | ctx->argv[1]); | |
a699f614 EJ |
1655 | set_external_id(&port->port_cfg->external_ids, &new, |
1656 | key, ctx->argc >= 4 ? ctx->argv[3] : NULL); | |
f74055e7 | 1657 | ovsrec_port_verify_external_ids(port->port_cfg); |
a699f614 | 1658 | ovsrec_port_set_external_ids(port->port_cfg, &new); |
457e1eb0 BP |
1659 | free(key); |
1660 | } | |
a699f614 | 1661 | smap_destroy(&new); |
457e1eb0 BP |
1662 | } |
1663 | ||
1664 | static void | |
a699f614 | 1665 | get_external_id(struct smap *smap, const char *prefix, const char *key, |
457e1eb0 BP |
1666 | struct ds *output) |
1667 | { | |
a699f614 EJ |
1668 | if (key) { |
1669 | char *prefix_key = xasprintf("%s%s", prefix, key); | |
1670 | const char *value = smap_get(smap, prefix_key); | |
457e1eb0 | 1671 | |
a699f614 EJ |
1672 | if (value) { |
1673 | ds_put_format(output, "%s\n", value); | |
1674 | } | |
1675 | free(prefix_key); | |
1676 | } else { | |
1677 | const struct smap_node **sorted = smap_sort(smap); | |
1678 | size_t prefix_len = strlen(prefix); | |
1679 | size_t i; | |
1680 | ||
1681 | for (i = 0; i < smap_count(smap); i++) { | |
1682 | const struct smap_node *node = sorted[i]; | |
1683 | if (!strncmp(node->key, prefix, prefix_len)) { | |
1684 | ds_put_format(output, "%s=%s\n", node->key + prefix_len, | |
1685 | node->value); | |
1686 | } | |
457e1eb0 | 1687 | } |
a699f614 | 1688 | free(sorted); |
457e1eb0 | 1689 | } |
457e1eb0 BP |
1690 | } |
1691 | ||
e5e12280 | 1692 | static void |
07ff77cc | 1693 | pre_cmd_br_get_external_id(struct ctl_context *ctx) |
e5e12280 BP |
1694 | { |
1695 | pre_cmd_br_set_external_id(ctx); | |
1696 | } | |
1697 | ||
457e1eb0 | 1698 | static void |
07ff77cc | 1699 | cmd_br_get_external_id(struct ctl_context *ctx) |
457e1eb0 | 1700 | { |
07ff77cc | 1701 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
457e1eb0 BP |
1702 | struct vsctl_bridge *bridge; |
1703 | ||
5ce5a6b5 BP |
1704 | vsctl_context_populate_cache(ctx); |
1705 | ||
07ff77cc | 1706 | bridge = find_bridge(vsctl_ctx, ctx->argv[1], true); |
457e1eb0 | 1707 | if (bridge->br_cfg) { |
f74055e7 | 1708 | ovsrec_bridge_verify_external_ids(bridge->br_cfg); |
a699f614 EJ |
1709 | get_external_id(&bridge->br_cfg->external_ids, "", |
1710 | ctx->argc >= 3 ? ctx->argv[2] : NULL, &ctx->output); | |
457e1eb0 | 1711 | } else { |
07ff77cc AW |
1712 | struct vsctl_port *port = shash_find_data(&vsctl_ctx->ports, |
1713 | ctx->argv[1]); | |
f74055e7 | 1714 | ovsrec_port_verify_external_ids(port->port_cfg); |
a699f614 EJ |
1715 | get_external_id(&port->port_cfg->external_ids, "fake-bridge-", |
1716 | ctx->argc >= 3 ? ctx->argv[2] : NULL, &ctx->output); | |
457e1eb0 | 1717 | } |
457e1eb0 BP |
1718 | } |
1719 | ||
c75d1511 | 1720 | static void |
07ff77cc | 1721 | cmd_list_ports(struct ctl_context *ctx) |
c75d1511 | 1722 | { |
07ff77cc | 1723 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
c75d1511 | 1724 | struct vsctl_bridge *br; |
a341ee57 | 1725 | struct vsctl_port *port; |
dfbe07ba | 1726 | struct svec ports; |
c75d1511 | 1727 | |
5ce5a6b5 | 1728 | vsctl_context_populate_cache(ctx); |
07ff77cc | 1729 | br = find_bridge(vsctl_ctx, ctx->argv[1], true); |
f74055e7 | 1730 | ovsrec_bridge_verify_ports(br->br_cfg ? br->br_cfg : br->parent->br_cfg); |
dfbe07ba BP |
1731 | |
1732 | svec_init(&ports); | |
a341ee57 BP |
1733 | LIST_FOR_EACH (port, ports_node, &br->ports) { |
1734 | if (strcmp(port->port_cfg->name, br->name)) { | |
dfbe07ba | 1735 | svec_add(&ports, port->port_cfg->name); |
c75d1511 BP |
1736 | } |
1737 | } | |
5d9cb63c | 1738 | output_sorted(&ports, &ctx->output); |
dfbe07ba | 1739 | svec_destroy(&ports); |
c75d1511 BP |
1740 | } |
1741 | ||
1742 | static void | |
07ff77cc | 1743 | add_port(struct ctl_context *ctx, |
bb1c67c8 BP |
1744 | const char *br_name, const char *port_name, |
1745 | bool may_exist, bool fake_iface, | |
18b239f5 BP |
1746 | char *iface_names[], int n_ifaces, |
1747 | char *settings[], int n_settings) | |
c75d1511 | 1748 | { |
07ff77cc | 1749 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
c75d1511 BP |
1750 | struct vsctl_bridge *bridge; |
1751 | struct ovsrec_interface **ifaces; | |
1752 | struct ovsrec_port *port; | |
1753 | size_t i; | |
1754 | ||
f75612a1 BP |
1755 | if (!port_name[0]) { |
1756 | ctl_fatal("port name must not be empty string"); | |
1757 | } | |
1758 | for (i = 0; i < n_ifaces; i++) { | |
1759 | if (!iface_names[i][0]) { | |
1760 | ctl_fatal("interface name must not be empty string"); | |
1761 | } | |
1762 | } | |
1763 | ||
5ce5a6b5 | 1764 | vsctl_context_populate_cache(ctx); |
bb1c67c8 | 1765 | if (may_exist) { |
2a022368 | 1766 | struct vsctl_port *vsctl_port; |
bb1c67c8 | 1767 | |
07ff77cc | 1768 | vsctl_port = find_port(vsctl_ctx, port_name, false); |
2a022368 | 1769 | if (vsctl_port) { |
bb1c67c8 | 1770 | struct svec want_names, have_names; |
bb1c67c8 BP |
1771 | |
1772 | svec_init(&want_names); | |
1773 | for (i = 0; i < n_ifaces; i++) { | |
1774 | svec_add(&want_names, iface_names[i]); | |
1775 | } | |
1776 | svec_sort(&want_names); | |
1777 | ||
1778 | svec_init(&have_names); | |
2a022368 BP |
1779 | for (i = 0; i < vsctl_port->port_cfg->n_interfaces; i++) { |
1780 | svec_add(&have_names, | |
1781 | vsctl_port->port_cfg->interfaces[i]->name); | |
bb1c67c8 BP |
1782 | } |
1783 | svec_sort(&have_names); | |
1784 | ||
2a022368 | 1785 | if (strcmp(vsctl_port->bridge->name, br_name)) { |
bb1c67c8 | 1786 | char *command = vsctl_context_to_string(ctx); |
07ff77cc | 1787 | ctl_fatal("\"%s\" but %s is actually attached to bridge %s", |
2a022368 | 1788 | command, port_name, vsctl_port->bridge->name); |
bb1c67c8 BP |
1789 | } |
1790 | ||
1791 | if (!svec_equal(&want_names, &have_names)) { | |
1792 | char *have_names_string = svec_join(&have_names, ", ", ""); | |
1793 | char *command = vsctl_context_to_string(ctx); | |
1794 | ||
07ff77cc | 1795 | ctl_fatal("\"%s\" but %s actually has interface(s) %s", |
bb1c67c8 BP |
1796 | command, port_name, have_names_string); |
1797 | } | |
1798 | ||
1799 | svec_destroy(&want_names); | |
1800 | svec_destroy(&have_names); | |
1801 | ||
1802 | return; | |
1803 | } | |
1804 | } | |
07ff77cc | 1805 | check_conflicts(vsctl_ctx, port_name, |
c75d1511 | 1806 | xasprintf("cannot create a port named %s", port_name)); |
bb1c67c8 | 1807 | for (i = 0; i < n_ifaces; i++) { |
07ff77cc | 1808 | check_conflicts(vsctl_ctx, iface_names[i], |
bb1c67c8 BP |
1809 | xasprintf("cannot create an interface named %s", |
1810 | iface_names[i])); | |
1811 | } | |
07ff77cc | 1812 | bridge = find_bridge(vsctl_ctx, br_name, true); |
c75d1511 BP |
1813 | |
1814 | ifaces = xmalloc(n_ifaces * sizeof *ifaces); | |
1815 | for (i = 0; i < n_ifaces; i++) { | |
f8ff4bc4 | 1816 | ifaces[i] = ovsrec_interface_insert(ctx->txn); |
c75d1511 | 1817 | ovsrec_interface_set_name(ifaces[i], iface_names[i]); |
c3ccfe98 | 1818 | post_db_reload_expect_iface(ifaces[i]); |
c75d1511 BP |
1819 | } |
1820 | ||
f8ff4bc4 | 1821 | port = ovsrec_port_insert(ctx->txn); |
c75d1511 BP |
1822 | ovsrec_port_set_name(port, port_name); |
1823 | ovsrec_port_set_interfaces(port, ifaces, n_ifaces); | |
b4182c7f | 1824 | ovsrec_port_set_bond_fake_iface(port, fake_iface); |
a0a9f31d | 1825 | |
5341d046 | 1826 | if (bridge->parent) { |
c75d1511 BP |
1827 | int64_t tag = bridge->vlan; |
1828 | ovsrec_port_set_tag(port, &tag, 1); | |
1829 | } | |
1830 | ||
18b239f5 | 1831 | for (i = 0; i < n_settings; i++) { |
fd26f9a2 JS |
1832 | char *error = ctl_set_column("Port", &port->header_, settings[i], |
1833 | ctx->symtab); | |
1834 | if (error) { | |
1835 | ctl_fatal("%s", error); | |
1836 | } | |
18b239f5 BP |
1837 | } |
1838 | ||
c75d1511 BP |
1839 | bridge_insert_port((bridge->parent ? bridge->parent->br_cfg |
1840 | : bridge->br_cfg), port); | |
1841 | ||
71f21279 | 1842 | struct vsctl_port *vsctl_port = add_port_to_cache(vsctl_ctx, bridge, port); |
a341ee57 | 1843 | for (i = 0; i < n_ifaces; i++) { |
07ff77cc | 1844 | add_iface_to_cache(vsctl_ctx, vsctl_port, ifaces[i]); |
a341ee57 BP |
1845 | } |
1846 | free(ifaces); | |
c75d1511 BP |
1847 | } |
1848 | ||
1849 | static void | |
07ff77cc | 1850 | cmd_add_port(struct ctl_context *ctx) |
c75d1511 | 1851 | { |
e3c17733 | 1852 | bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; |
bb1c67c8 BP |
1853 | |
1854 | add_port(ctx, ctx->argv[1], ctx->argv[2], may_exist, false, | |
18b239f5 | 1855 | &ctx->argv[2], 1, &ctx->argv[3], ctx->argc - 3); |
c75d1511 BP |
1856 | } |
1857 | ||
1858 | static void | |
07ff77cc | 1859 | cmd_add_bond(struct ctl_context *ctx) |
c75d1511 | 1860 | { |
e3c17733 | 1861 | bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; |
b4182c7f | 1862 | bool fake_iface = shash_find(&ctx->options, "--fake-iface"); |
18b239f5 BP |
1863 | int n_ifaces; |
1864 | int i; | |
1865 | ||
1866 | n_ifaces = ctx->argc - 3; | |
1867 | for (i = 3; i < ctx->argc; i++) { | |
1868 | if (strchr(ctx->argv[i], '=')) { | |
1869 | n_ifaces = i - 3; | |
1870 | break; | |
1871 | } | |
1872 | } | |
1873 | if (n_ifaces < 2) { | |
07ff77cc | 1874 | ctl_fatal("add-bond requires at least 2 interfaces, but only " |
18b239f5 BP |
1875 | "%d were specified", n_ifaces); |
1876 | } | |
b4182c7f | 1877 | |
bb1c67c8 | 1878 | add_port(ctx, ctx->argv[1], ctx->argv[2], may_exist, fake_iface, |
18b239f5 BP |
1879 | &ctx->argv[3], n_ifaces, |
1880 | &ctx->argv[n_ifaces + 3], ctx->argc - 3 - n_ifaces); | |
c75d1511 BP |
1881 | } |
1882 | ||
ec5ef1cf BP |
1883 | static void |
1884 | cmd_add_bond_iface(struct ctl_context *ctx) | |
1885 | { | |
1886 | vsctl_context_populate_cache(ctx); | |
1887 | ||
1888 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); | |
1889 | bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; | |
1890 | struct vsctl_port *port = find_port(vsctl_ctx, ctx->argv[1], true); | |
1891 | ||
1892 | const char *iface_name = ctx->argv[2]; | |
1893 | if (may_exist) { | |
1894 | struct vsctl_iface *iface = find_iface(vsctl_ctx, iface_name, false); | |
1895 | if (iface) { | |
1896 | if (iface->port == port) { | |
1897 | return; | |
1898 | } | |
1899 | char *command = vsctl_context_to_string(ctx); | |
1900 | ctl_fatal("\"%s\" but %s is actually attached to port %s", | |
1901 | command, iface_name, iface->port->port_cfg->name); | |
1902 | } | |
1903 | } | |
1904 | check_conflicts(vsctl_ctx, iface_name, | |
1905 | xasprintf("cannot create an interface named %s", | |
1906 | iface_name)); | |
1907 | ||
1908 | struct ovsrec_interface *iface = ovsrec_interface_insert(ctx->txn); | |
1909 | ovsrec_interface_set_name(iface, iface_name); | |
1910 | ovsrec_port_update_interfaces_addvalue(port->port_cfg, iface); | |
1911 | post_db_reload_expect_iface(iface); | |
1912 | add_iface_to_cache(vsctl_ctx, port, iface); | |
1913 | } | |
1914 | ||
1915 | static void | |
1916 | cmd_del_bond_iface(struct ctl_context *ctx) | |
1917 | { | |
1918 | vsctl_context_populate_cache(ctx); | |
1919 | ||
1920 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); | |
1921 | const char *iface_name = ctx->argv[ctx->argc - 1]; | |
1922 | bool must_exist = !shash_find(&ctx->options, "--if-exists"); | |
1923 | struct vsctl_iface *iface = find_iface(vsctl_ctx, iface_name, must_exist); | |
1924 | if (!iface) { | |
1925 | ovs_assert(!must_exist); | |
1926 | return; | |
1927 | } | |
1928 | ||
1929 | const char *port_name = ctx->argc > 2 ? ctx->argv[1] : NULL; | |
1930 | if (port_name) { | |
1931 | struct vsctl_port *port = find_port(vsctl_ctx, port_name, true); | |
1932 | if (iface->port != port) { | |
1933 | ctl_fatal("port %s does not have an interface %s", | |
1934 | port_name, iface_name); | |
1935 | } | |
1936 | } | |
1937 | ||
1938 | if (ovs_list_is_short(&iface->port->ifaces)) { | |
1939 | ctl_fatal("cannot delete last interface from port %s", | |
1940 | iface->port->port_cfg->name); | |
1941 | } | |
1942 | ||
1943 | ovsrec_port_update_interfaces_delvalue(iface->port->port_cfg, | |
1944 | iface->iface_cfg); | |
1945 | del_cached_iface(vsctl_ctx, iface); | |
1946 | } | |
1947 | ||
c75d1511 | 1948 | static void |
07ff77cc | 1949 | cmd_del_port(struct ctl_context *ctx) |
c75d1511 | 1950 | { |
07ff77cc | 1951 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
460aad80 | 1952 | bool must_exist = !shash_find(&ctx->options, "--if-exists"); |
7c79588e | 1953 | bool with_iface = shash_find(&ctx->options, "--with-iface") != NULL; |
89f3c258 | 1954 | const char *target = ctx->argv[ctx->argc - 1]; |
7c79588e | 1955 | struct vsctl_port *port; |
c75d1511 | 1956 | |
5ce5a6b5 | 1957 | vsctl_context_populate_cache(ctx); |
07ff77cc | 1958 | if (find_bridge(vsctl_ctx, target, false)) { |
25a27ba0 | 1959 | if (must_exist) { |
07ff77cc | 1960 | ctl_fatal("cannot delete port %s because it is the local port " |
25a27ba0 BP |
1961 | "for bridge %s (deleting this port requires deleting " |
1962 | "the entire bridge)", target, target); | |
1963 | } | |
1964 | port = NULL; | |
89f3c258 | 1965 | } else if (!with_iface) { |
07ff77cc | 1966 | port = find_port(vsctl_ctx, target, must_exist); |
7c79588e | 1967 | } else { |
7c79588e BP |
1968 | struct vsctl_iface *iface; |
1969 | ||
07ff77cc | 1970 | port = find_port(vsctl_ctx, target, false); |
7c79588e | 1971 | if (!port) { |
07ff77cc | 1972 | iface = find_iface(vsctl_ctx, target, false); |
7c79588e BP |
1973 | if (iface) { |
1974 | port = iface->port; | |
1975 | } | |
1976 | } | |
1977 | if (must_exist && !port) { | |
07ff77cc | 1978 | ctl_fatal("no port or interface named %s", target); |
460aad80 | 1979 | } |
7c79588e | 1980 | } |
460aad80 | 1981 | |
7c79588e BP |
1982 | if (port) { |
1983 | if (ctx->argc == 3) { | |
1984 | struct vsctl_bridge *bridge; | |
1985 | ||
07ff77cc | 1986 | bridge = find_bridge(vsctl_ctx, ctx->argv[1], true); |
7c79588e BP |
1987 | if (port->bridge != bridge) { |
1988 | if (port->bridge->parent == bridge) { | |
07ff77cc | 1989 | ctl_fatal("bridge %s does not have a port %s (although " |
09f37a1b | 1990 | "its child bridge %s does)", |
7c79588e | 1991 | ctx->argv[1], ctx->argv[2], |
09f37a1b | 1992 | port->bridge->name); |
7c79588e | 1993 | } else { |
07ff77cc | 1994 | ctl_fatal("bridge %s does not have a port %s", |
7c79588e BP |
1995 | ctx->argv[1], ctx->argv[2]); |
1996 | } | |
460aad80 | 1997 | } |
c75d1511 | 1998 | } |
7c79588e | 1999 | |
07ff77cc | 2000 | del_port(vsctl_ctx, port); |
c75d1511 | 2001 | } |
c75d1511 BP |
2002 | } |
2003 | ||
2004 | static void | |
07ff77cc | 2005 | cmd_port_to_br(struct ctl_context *ctx) |
c75d1511 | 2006 | { |
07ff77cc | 2007 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
c75d1511 | 2008 | struct vsctl_port *port; |
c75d1511 | 2009 | |
5ce5a6b5 BP |
2010 | vsctl_context_populate_cache(ctx); |
2011 | ||
07ff77cc | 2012 | port = find_port(vsctl_ctx, ctx->argv[1], true); |
5d9cb63c | 2013 | ds_put_format(&ctx->output, "%s\n", port->bridge->name); |
c75d1511 BP |
2014 | } |
2015 | ||
2016 | static void | |
07ff77cc | 2017 | cmd_br_to_vlan(struct ctl_context *ctx) |
c75d1511 | 2018 | { |
07ff77cc | 2019 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
c75d1511 | 2020 | struct vsctl_bridge *bridge; |
c75d1511 | 2021 | |
5ce5a6b5 BP |
2022 | vsctl_context_populate_cache(ctx); |
2023 | ||
07ff77cc | 2024 | bridge = find_bridge(vsctl_ctx, ctx->argv[1], true); |
5d9cb63c | 2025 | ds_put_format(&ctx->output, "%d\n", bridge->vlan); |
c75d1511 BP |
2026 | } |
2027 | ||
2028 | static void | |
07ff77cc | 2029 | cmd_br_to_parent(struct ctl_context *ctx) |
c75d1511 | 2030 | { |
07ff77cc | 2031 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
c75d1511 | 2032 | struct vsctl_bridge *bridge; |
c75d1511 | 2033 | |
5ce5a6b5 BP |
2034 | vsctl_context_populate_cache(ctx); |
2035 | ||
07ff77cc | 2036 | bridge = find_bridge(vsctl_ctx, ctx->argv[1], true); |
c75d1511 BP |
2037 | if (bridge->parent) { |
2038 | bridge = bridge->parent; | |
2039 | } | |
5d9cb63c | 2040 | ds_put_format(&ctx->output, "%s\n", bridge->name); |
c75d1511 BP |
2041 | } |
2042 | ||
2043 | static void | |
07ff77cc | 2044 | cmd_list_ifaces(struct ctl_context *ctx) |
c75d1511 | 2045 | { |
07ff77cc | 2046 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
c75d1511 | 2047 | struct vsctl_bridge *br; |
a341ee57 | 2048 | struct vsctl_port *port; |
dfbe07ba | 2049 | struct svec ifaces; |
c75d1511 | 2050 | |
5ce5a6b5 BP |
2051 | vsctl_context_populate_cache(ctx); |
2052 | ||
07ff77cc AW |
2053 | br = find_bridge(vsctl_ctx, ctx->argv[1], true); |
2054 | verify_ports(vsctl_ctx); | |
dfbe07ba BP |
2055 | |
2056 | svec_init(&ifaces); | |
a341ee57 BP |
2057 | LIST_FOR_EACH (port, ports_node, &br->ports) { |
2058 | struct vsctl_iface *iface; | |
c75d1511 | 2059 | |
a341ee57 BP |
2060 | LIST_FOR_EACH (iface, ifaces_node, &port->ifaces) { |
2061 | if (strcmp(iface->iface_cfg->name, br->name)) { | |
2062 | svec_add(&ifaces, iface->iface_cfg->name); | |
2063 | } | |
c75d1511 BP |
2064 | } |
2065 | } | |
5d9cb63c | 2066 | output_sorted(&ifaces, &ctx->output); |
dfbe07ba | 2067 | svec_destroy(&ifaces); |
c75d1511 BP |
2068 | } |
2069 | ||
2070 | static void | |
07ff77cc | 2071 | cmd_iface_to_br(struct ctl_context *ctx) |
c75d1511 | 2072 | { |
07ff77cc | 2073 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
c75d1511 | 2074 | struct vsctl_iface *iface; |
c75d1511 | 2075 | |
5ce5a6b5 BP |
2076 | vsctl_context_populate_cache(ctx); |
2077 | ||
07ff77cc | 2078 | iface = find_iface(vsctl_ctx, ctx->argv[1], true); |
5d9cb63c | 2079 | ds_put_format(&ctx->output, "%s\n", iface->port->bridge->name); |
c75d1511 | 2080 | } |
457e1eb0 | 2081 | |
f74055e7 BP |
2082 | static void |
2083 | verify_controllers(struct ovsrec_bridge *bridge) | |
2084 | { | |
7da6c3a6 | 2085 | size_t i; |
f74055e7 | 2086 | |
7da6c3a6 BP |
2087 | ovsrec_bridge_verify_controller(bridge); |
2088 | for (i = 0; i < bridge->n_controller; i++) { | |
2089 | ovsrec_controller_verify_target(bridge->controller[i]); | |
f74055e7 BP |
2090 | } |
2091 | } | |
2092 | ||
4e3e7ff9 | 2093 | static void |
07ff77cc | 2094 | pre_controller(struct ctl_context *ctx) |
4e3e7ff9 BP |
2095 | { |
2096 | pre_get_info(ctx); | |
2097 | ||
2098 | ovsdb_idl_add_column(ctx->idl, &ovsrec_controller_col_target); | |
3ffed5cb | 2099 | ovsdb_idl_add_column(ctx->idl, &ovsrec_controller_col_inactivity_probe); |
4e3e7ff9 BP |
2100 | } |
2101 | ||
76ce9432 | 2102 | static void |
07ff77cc | 2103 | cmd_get_controller(struct ctl_context *ctx) |
76ce9432 | 2104 | { |
07ff77cc | 2105 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
1a048029 | 2106 | struct vsctl_bridge *br; |
76ce9432 BP |
2107 | struct svec targets; |
2108 | size_t i; | |
2109 | ||
5ce5a6b5 BP |
2110 | vsctl_context_populate_cache(ctx); |
2111 | ||
07ff77cc | 2112 | br = find_bridge(vsctl_ctx, ctx->argv[1], true); |
7da6c3a6 BP |
2113 | if (br->parent) { |
2114 | br = br->parent; | |
2115 | } | |
f74055e7 | 2116 | verify_controllers(br->br_cfg); |
1a048029 JP |
2117 | |
2118 | /* Print the targets in sorted order for reproducibility. */ | |
76ce9432 | 2119 | svec_init(&targets); |
286a2e82 BP |
2120 | for (i = 0; i < br->br_cfg->n_controller; i++) { |
2121 | svec_add(&targets, br->br_cfg->controller[i]->target); | |
76ce9432 BP |
2122 | } |
2123 | ||
2124 | svec_sort(&targets); | |
2125 | for (i = 0; i < targets.n; i++) { | |
2126 | ds_put_format(&ctx->output, "%s\n", targets.names[i]); | |
2127 | } | |
2128 | svec_destroy(&targets); | |
5aa00635 JP |
2129 | } |
2130 | ||
28a14bf3 EJ |
2131 | static void |
2132 | delete_controllers(struct ovsrec_controller **controllers, | |
2133 | size_t n_controllers) | |
2134 | { | |
2135 | size_t i; | |
2136 | ||
2137 | for (i = 0; i < n_controllers; i++) { | |
2138 | ovsrec_controller_delete(controllers[i]); | |
2139 | } | |
2140 | } | |
2141 | ||
5aa00635 | 2142 | static void |
07ff77cc | 2143 | cmd_del_controller(struct ctl_context *ctx) |
5aa00635 | 2144 | { |
07ff77cc | 2145 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
286a2e82 | 2146 | struct ovsrec_bridge *br; |
5aa00635 | 2147 | |
5ce5a6b5 | 2148 | vsctl_context_populate_cache(ctx); |
5aa00635 | 2149 | |
07ff77cc | 2150 | br = find_real_bridge(vsctl_ctx, ctx->argv[1], true)->br_cfg; |
286a2e82 | 2151 | verify_controllers(br); |
5aa00635 | 2152 | |
286a2e82 BP |
2153 | if (br->controller) { |
2154 | delete_controllers(br->controller, br->n_controller); | |
2155 | ovsrec_bridge_set_controller(br, NULL, 0); | |
5ce5a6b5 | 2156 | } |
5aa00635 JP |
2157 | } |
2158 | ||
76ce9432 | 2159 | static struct ovsrec_controller ** |
3ffed5cb | 2160 | insert_controllers(struct ctl_context *ctx, char *targets[], size_t n) |
76ce9432 BP |
2161 | { |
2162 | struct ovsrec_controller **controllers; | |
2163 | size_t i; | |
3ffed5cb GL |
2164 | const char *inactivity_probe = shash_find_data(&ctx->options, |
2165 | "--inactivity-probe"); | |
76ce9432 BP |
2166 | |
2167 | controllers = xmalloc(n * sizeof *controllers); | |
2168 | for (i = 0; i < n; i++) { | |
070723f9 JP |
2169 | if (vconn_verify_name(targets[i]) && pvconn_verify_name(targets[i])) { |
2170 | VLOG_WARN("target type \"%s\" is possibly erroneous", targets[i]); | |
2171 | } | |
3ffed5cb | 2172 | controllers[i] = ovsrec_controller_insert(ctx->txn); |
76ce9432 | 2173 | ovsrec_controller_set_target(controllers[i], targets[i]); |
3ffed5cb GL |
2174 | if (inactivity_probe) { |
2175 | int64_t msecs = atoll(inactivity_probe); | |
2176 | ovsrec_controller_set_inactivity_probe(controllers[i], &msecs, 1); | |
2177 | } | |
76ce9432 BP |
2178 | } |
2179 | ||
2180 | return controllers; | |
2181 | } | |
2182 | ||
5aa00635 | 2183 | static void |
07ff77cc | 2184 | cmd_set_controller(struct ctl_context *ctx) |
5aa00635 | 2185 | { |
07ff77cc | 2186 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
1a048029 | 2187 | struct ovsrec_controller **controllers; |
286a2e82 | 2188 | struct ovsrec_bridge *br; |
1a048029 | 2189 | size_t n; |
5aa00635 | 2190 | |
5ce5a6b5 BP |
2191 | vsctl_context_populate_cache(ctx); |
2192 | ||
07ff77cc | 2193 | br = find_real_bridge(vsctl_ctx, ctx->argv[1], true)->br_cfg; |
286a2e82 | 2194 | verify_controllers(br); |
28a14bf3 | 2195 | |
286a2e82 | 2196 | delete_controllers(br->controller, br->n_controller); |
76ce9432 | 2197 | |
1a048029 | 2198 | n = ctx->argc - 2; |
3ffed5cb | 2199 | controllers = insert_controllers(ctx, &ctx->argv[2], n); |
286a2e82 | 2200 | ovsrec_bridge_set_controller(br, controllers, n); |
1a048029 | 2201 | free(controllers); |
5aa00635 JP |
2202 | } |
2203 | ||
2204 | static void | |
07ff77cc | 2205 | cmd_get_fail_mode(struct ctl_context *ctx) |
5aa00635 | 2206 | { |
07ff77cc | 2207 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
1a048029 | 2208 | struct vsctl_bridge *br; |
753cb20f | 2209 | const char *fail_mode; |
5aa00635 | 2210 | |
5ce5a6b5 | 2211 | vsctl_context_populate_cache(ctx); |
07ff77cc | 2212 | br = find_bridge(vsctl_ctx, ctx->argv[1], true); |
5aa00635 | 2213 | |
753cb20f BP |
2214 | if (br->parent) { |
2215 | br = br->parent; | |
2216 | } | |
2217 | ovsrec_bridge_verify_fail_mode(br->br_cfg); | |
2218 | ||
2219 | fail_mode = br->br_cfg->fail_mode; | |
2220 | if (fail_mode && strlen(fail_mode)) { | |
2221 | ds_put_format(&ctx->output, "%s\n", fail_mode); | |
5aa00635 | 2222 | } |
5aa00635 JP |
2223 | } |
2224 | ||
2225 | static void | |
07ff77cc | 2226 | cmd_del_fail_mode(struct ctl_context *ctx) |
5aa00635 | 2227 | { |
07ff77cc | 2228 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
1a048029 | 2229 | struct vsctl_bridge *br; |
5aa00635 | 2230 | |
5ce5a6b5 | 2231 | vsctl_context_populate_cache(ctx); |
5aa00635 | 2232 | |
07ff77cc | 2233 | br = find_real_bridge(vsctl_ctx, ctx->argv[1], true); |
5aa00635 | 2234 | |
5ce5a6b5 | 2235 | ovsrec_bridge_set_fail_mode(br->br_cfg, NULL); |
5aa00635 JP |
2236 | } |
2237 | ||
2238 | static void | |
07ff77cc | 2239 | cmd_set_fail_mode(struct ctl_context *ctx) |
5aa00635 | 2240 | { |
07ff77cc | 2241 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
1a048029 JP |
2242 | struct vsctl_bridge *br; |
2243 | const char *fail_mode = ctx->argv[2]; | |
5aa00635 | 2244 | |
5ce5a6b5 BP |
2245 | vsctl_context_populate_cache(ctx); |
2246 | ||
07ff77cc | 2247 | br = find_real_bridge(vsctl_ctx, ctx->argv[1], true); |
5aa00635 JP |
2248 | |
2249 | if (strcmp(fail_mode, "standalone") && strcmp(fail_mode, "secure")) { | |
07ff77cc | 2250 | ctl_fatal("fail-mode must be \"standalone\" or \"secure\""); |
5aa00635 JP |
2251 | } |
2252 | ||
31681a5d | 2253 | ovsrec_bridge_set_fail_mode(br->br_cfg, fail_mode); |
5aa00635 | 2254 | } |
dd8ac6fe | 2255 | |
24b8b259 AE |
2256 | static void |
2257 | verify_managers(const struct ovsrec_open_vswitch *ovs) | |
2258 | { | |
2259 | size_t i; | |
2260 | ||
24b8b259 AE |
2261 | ovsrec_open_vswitch_verify_manager_options(ovs); |
2262 | ||
2263 | for (i = 0; i < ovs->n_manager_options; ++i) { | |
2264 | const struct ovsrec_manager *mgr = ovs->manager_options[i]; | |
2265 | ||
2266 | ovsrec_manager_verify_target(mgr); | |
2267 | } | |
2268 | } | |
2269 | ||
2270 | static void | |
07ff77cc | 2271 | pre_manager(struct ctl_context *ctx) |
24b8b259 | 2272 | { |
24b8b259 AE |
2273 | ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_manager_options); |
2274 | ovsdb_idl_add_column(ctx->idl, &ovsrec_manager_col_target); | |
3ffed5cb | 2275 | ovsdb_idl_add_column(ctx->idl, &ovsrec_manager_col_inactivity_probe); |
24b8b259 AE |
2276 | } |
2277 | ||
2278 | static void | |
07ff77cc | 2279 | cmd_get_manager(struct ctl_context *ctx) |
24b8b259 | 2280 | { |
07ff77cc AW |
2281 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
2282 | const struct ovsrec_open_vswitch *ovs = vsctl_ctx->ovs; | |
24b8b259 AE |
2283 | struct svec targets; |
2284 | size_t i; | |
2285 | ||
2286 | verify_managers(ovs); | |
2287 | ||
2288 | /* Print the targets in sorted order for reproducibility. */ | |
2289 | svec_init(&targets); | |
2290 | ||
24b8b259 AE |
2291 | for (i = 0; i < ovs->n_manager_options; i++) { |
2292 | svec_add(&targets, ovs->manager_options[i]->target); | |
2293 | } | |
2294 | ||
2295 | svec_sort_unique(&targets); | |
2296 | for (i = 0; i < targets.n; i++) { | |
2297 | ds_put_format(&ctx->output, "%s\n", targets.names[i]); | |
2298 | } | |
2299 | svec_destroy(&targets); | |
2300 | } | |
2301 | ||
24b8b259 | 2302 | static void |
29c3a9f5 | 2303 | delete_managers(const struct ovsrec_open_vswitch *ovs) |
24b8b259 | 2304 | { |
28a14bf3 EJ |
2305 | size_t i; |
2306 | ||
2307 | /* Delete Manager rows pointed to by 'manager_options' column. */ | |
2308 | for (i = 0; i < ovs->n_manager_options; i++) { | |
2309 | ovsrec_manager_delete(ovs->manager_options[i]); | |
2310 | } | |
24b8b259 | 2311 | |
28a14bf3 | 2312 | /* Delete 'Manager' row refs in 'manager_options' column. */ |
c5f341ab | 2313 | ovsrec_open_vswitch_set_manager_options(ovs, NULL, 0); |
24b8b259 AE |
2314 | } |
2315 | ||
28a14bf3 | 2316 | static void |
07ff77cc | 2317 | cmd_del_manager(struct ctl_context *ctx) |
28a14bf3 | 2318 | { |
07ff77cc AW |
2319 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
2320 | const struct ovsrec_open_vswitch *ovs = vsctl_ctx->ovs; | |
28a14bf3 EJ |
2321 | |
2322 | verify_managers(ovs); | |
29c3a9f5 | 2323 | delete_managers(ovs); |
28a14bf3 EJ |
2324 | } |
2325 | ||
24b8b259 | 2326 | static void |
3ffed5cb GL |
2327 | insert_managers(struct vsctl_context *vsctl_ctx, char *targets[], size_t n, |
2328 | struct shash *options) | |
24b8b259 AE |
2329 | { |
2330 | struct ovsrec_manager **managers; | |
2331 | size_t i; | |
3ffed5cb GL |
2332 | const char *inactivity_probe = shash_find_data(options, |
2333 | "--inactivity-probe"); | |
24b8b259 | 2334 | |
24b8b259 AE |
2335 | /* Insert each manager in a new row in Manager table. */ |
2336 | managers = xmalloc(n * sizeof *managers); | |
2337 | for (i = 0; i < n; i++) { | |
070723f9 JP |
2338 | if (stream_verify_name(targets[i]) && pstream_verify_name(targets[i])) { |
2339 | VLOG_WARN("target type \"%s\" is possibly erroneous", targets[i]); | |
2340 | } | |
07ff77cc | 2341 | managers[i] = ovsrec_manager_insert(vsctl_ctx->base.txn); |
24b8b259 | 2342 | ovsrec_manager_set_target(managers[i], targets[i]); |
3ffed5cb GL |
2343 | if (inactivity_probe) { |
2344 | int64_t msecs = atoll(inactivity_probe); | |
2345 | ovsrec_manager_set_inactivity_probe(managers[i], &msecs, 1); | |
2346 | } | |
24b8b259 AE |
2347 | } |
2348 | ||
2349 | /* Store uuids of new Manager rows in 'manager_options' column. */ | |
07ff77cc | 2350 | ovsrec_open_vswitch_set_manager_options(vsctl_ctx->ovs, managers, n); |
24b8b259 AE |
2351 | free(managers); |
2352 | } | |
2353 | ||
2354 | static void | |
07ff77cc | 2355 | cmd_set_manager(struct ctl_context *ctx) |
24b8b259 | 2356 | { |
07ff77cc | 2357 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
24b8b259 AE |
2358 | const size_t n = ctx->argc - 1; |
2359 | ||
07ff77cc AW |
2360 | verify_managers(vsctl_ctx->ovs); |
2361 | delete_managers(vsctl_ctx->ovs); | |
3ffed5cb | 2362 | insert_managers(vsctl_ctx, &ctx->argv[1], n, &ctx->options); |
24b8b259 AE |
2363 | } |
2364 | ||
e5e12280 | 2365 | static void |
07ff77cc | 2366 | pre_cmd_get_ssl(struct ctl_context *ctx) |
e5e12280 BP |
2367 | { |
2368 | ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_ssl); | |
2369 | ||
2370 | ovsdb_idl_add_column(ctx->idl, &ovsrec_ssl_col_private_key); | |
2371 | ovsdb_idl_add_column(ctx->idl, &ovsrec_ssl_col_certificate); | |
2372 | ovsdb_idl_add_column(ctx->idl, &ovsrec_ssl_col_ca_cert); | |
2373 | ovsdb_idl_add_column(ctx->idl, &ovsrec_ssl_col_bootstrap_ca_cert); | |
2374 | } | |
2375 | ||
dd8ac6fe | 2376 | static void |
07ff77cc | 2377 | cmd_get_ssl(struct ctl_context *ctx) |
dd8ac6fe | 2378 | { |
07ff77cc AW |
2379 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
2380 | struct ovsrec_ssl *ssl = vsctl_ctx->ovs->ssl; | |
dd8ac6fe | 2381 | |
07ff77cc | 2382 | ovsrec_open_vswitch_verify_ssl(vsctl_ctx->ovs); |
dd8ac6fe | 2383 | if (ssl) { |
f74055e7 BP |
2384 | ovsrec_ssl_verify_private_key(ssl); |
2385 | ovsrec_ssl_verify_certificate(ssl); | |
2386 | ovsrec_ssl_verify_ca_cert(ssl); | |
2387 | ovsrec_ssl_verify_bootstrap_ca_cert(ssl); | |
2388 | ||
dd8ac6fe JP |
2389 | ds_put_format(&ctx->output, "Private key: %s\n", ssl->private_key); |
2390 | ds_put_format(&ctx->output, "Certificate: %s\n", ssl->certificate); | |
2391 | ds_put_format(&ctx->output, "CA Certificate: %s\n", ssl->ca_cert); | |
2392 | ds_put_format(&ctx->output, "Bootstrap: %s\n", | |
2393 | ssl->bootstrap_ca_cert ? "true" : "false"); | |
2394 | } | |
2395 | } | |
2396 | ||
e5e12280 | 2397 | static void |
07ff77cc | 2398 | pre_cmd_del_ssl(struct ctl_context *ctx) |
e5e12280 BP |
2399 | { |
2400 | ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_ssl); | |
2401 | } | |
2402 | ||
dd8ac6fe | 2403 | static void |
07ff77cc | 2404 | cmd_del_ssl(struct ctl_context *ctx) |
dd8ac6fe | 2405 | { |
07ff77cc AW |
2406 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
2407 | struct ovsrec_ssl *ssl = vsctl_ctx->ovs->ssl; | |
28a14bf3 EJ |
2408 | |
2409 | if (ssl) { | |
07ff77cc | 2410 | ovsrec_open_vswitch_verify_ssl(vsctl_ctx->ovs); |
28a14bf3 | 2411 | ovsrec_ssl_delete(ssl); |
07ff77cc | 2412 | ovsrec_open_vswitch_set_ssl(vsctl_ctx->ovs, NULL); |
28a14bf3 | 2413 | } |
dd8ac6fe JP |
2414 | } |
2415 | ||
e5e12280 | 2416 | static void |
07ff77cc | 2417 | pre_cmd_set_ssl(struct ctl_context *ctx) |
e5e12280 BP |
2418 | { |
2419 | ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_ssl); | |
2420 | } | |
2421 | ||
dd8ac6fe | 2422 | static void |
07ff77cc | 2423 | cmd_set_ssl(struct ctl_context *ctx) |
dd8ac6fe | 2424 | { |
07ff77cc | 2425 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
dd8ac6fe | 2426 | bool bootstrap = shash_find(&ctx->options, "--bootstrap"); |
07ff77cc | 2427 | struct ovsrec_ssl *ssl = vsctl_ctx->ovs->ssl; |
dd8ac6fe | 2428 | |
07ff77cc | 2429 | ovsrec_open_vswitch_verify_ssl(vsctl_ctx->ovs); |
28a14bf3 EJ |
2430 | if (ssl) { |
2431 | ovsrec_ssl_delete(ssl); | |
2432 | } | |
f8ff4bc4 | 2433 | ssl = ovsrec_ssl_insert(ctx->txn); |
dd8ac6fe JP |
2434 | |
2435 | ovsrec_ssl_set_private_key(ssl, ctx->argv[1]); | |
2436 | ovsrec_ssl_set_certificate(ssl, ctx->argv[2]); | |
2437 | ovsrec_ssl_set_ca_cert(ssl, ctx->argv[3]); | |
2438 | ||
2439 | ovsrec_ssl_set_bootstrap_ca_cert(ssl, bootstrap); | |
2440 | ||
07ff77cc | 2441 | ovsrec_open_vswitch_set_ssl(vsctl_ctx->ovs, ssl); |
dd8ac6fe | 2442 | } |
99eef98b DF |
2443 | |
2444 | static void | |
2445 | autoattach_insert_mapping(struct ovsrec_autoattach *aa, | |
2446 | int64_t isid, | |
2447 | int64_t vlan) | |
2448 | { | |
2449 | int64_t *key_mappings, *value_mappings; | |
2450 | size_t i; | |
2451 | ||
2452 | key_mappings = xmalloc(sizeof *aa->key_mappings * (aa->n_mappings + 1)); | |
2453 | value_mappings = xmalloc(sizeof *aa->value_mappings * (aa->n_mappings + 1)); | |
2454 | ||
2455 | for (i = 0; i < aa->n_mappings; i++) { | |
2456 | key_mappings[i] = aa->key_mappings[i]; | |
2457 | value_mappings[i] = aa->value_mappings[i]; | |
2458 | } | |
2459 | key_mappings[aa->n_mappings] = isid; | |
2460 | value_mappings[aa->n_mappings] = vlan; | |
2461 | ||
2462 | ovsrec_autoattach_set_mappings(aa, key_mappings, value_mappings, | |
2463 | aa->n_mappings + 1); | |
2464 | ||
2465 | free(key_mappings); | |
2466 | free(value_mappings); | |
2467 | } | |
2468 | ||
2469 | static void | |
07ff77cc | 2470 | cmd_add_aa_mapping(struct ctl_context *ctx) |
99eef98b | 2471 | { |
07ff77cc | 2472 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
99eef98b DF |
2473 | struct vsctl_bridge *br; |
2474 | int64_t isid, vlan; | |
2475 | char *nptr = NULL; | |
2476 | ||
2477 | isid = strtoull(ctx->argv[2], &nptr, 10); | |
2478 | if (nptr == ctx->argv[2] || nptr == NULL) { | |
07ff77cc | 2479 | ctl_fatal("Invalid argument %s", ctx->argv[2]); |
99eef98b DF |
2480 | return; |
2481 | } | |
2482 | ||
2483 | vlan = strtoull(ctx->argv[3], &nptr, 10); | |
2484 | if (nptr == ctx->argv[3] || nptr == NULL) { | |
07ff77cc | 2485 | ctl_fatal("Invalid argument %s", ctx->argv[3]); |
99eef98b DF |
2486 | return; |
2487 | } | |
2488 | ||
2489 | vsctl_context_populate_cache(ctx); | |
2490 | ||
07ff77cc | 2491 | br = find_bridge(vsctl_ctx, ctx->argv[1], true); |
99eef98b DF |
2492 | if (br->parent) { |
2493 | br = br->parent; | |
2494 | } | |
2495 | ||
2bb0bea8 | 2496 | if (br->br_cfg) { |
c557ca04 BP |
2497 | if (!br->br_cfg->auto_attach) { |
2498 | struct ovsrec_autoattach *aa = ovsrec_autoattach_insert(ctx->txn); | |
2499 | ovsrec_bridge_set_auto_attach(br->br_cfg, aa); | |
2500 | } | |
99eef98b DF |
2501 | autoattach_insert_mapping(br->br_cfg->auto_attach, isid, vlan); |
2502 | } | |
2503 | } | |
2504 | ||
2505 | static void | |
2506 | del_aa_mapping(struct ovsrec_autoattach *aa, | |
2507 | int64_t isid, | |
2508 | int64_t vlan) | |
2509 | { | |
2510 | int64_t *key_mappings, *value_mappings; | |
2511 | size_t i, n; | |
2512 | ||
2513 | key_mappings = xmalloc(sizeof *aa->key_mappings * (aa->n_mappings)); | |
2514 | value_mappings = xmalloc(sizeof *value_mappings * (aa->n_mappings)); | |
2515 | ||
2516 | for (i = n = 0; i < aa->n_mappings; i++) { | |
2517 | if (aa->key_mappings[i] != isid && aa->value_mappings[i] != vlan) { | |
2518 | key_mappings[n] = aa->key_mappings[i]; | |
2519 | value_mappings[n++] = aa->value_mappings[i]; | |
2520 | } | |
2521 | } | |
2522 | ||
2523 | ovsrec_autoattach_set_mappings(aa, key_mappings, value_mappings, n); | |
2524 | ||
2525 | free(key_mappings); | |
2526 | free(value_mappings); | |
2527 | } | |
2528 | ||
2529 | static void | |
07ff77cc | 2530 | cmd_del_aa_mapping(struct ctl_context *ctx) |
99eef98b | 2531 | { |
07ff77cc | 2532 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
99eef98b DF |
2533 | struct vsctl_bridge *br; |
2534 | int64_t isid, vlan; | |
2535 | char *nptr = NULL; | |
2536 | ||
2537 | isid = strtoull(ctx->argv[2], &nptr, 10); | |
2538 | if (nptr == ctx->argv[2] || nptr == NULL) { | |
07ff77cc | 2539 | ctl_fatal("Invalid argument %s", ctx->argv[2]); |
99eef98b DF |
2540 | return; |
2541 | } | |
2542 | ||
2543 | vlan = strtoull(ctx->argv[3], &nptr, 10); | |
2544 | if (nptr == ctx->argv[3] || nptr == NULL) { | |
07ff77cc | 2545 | ctl_fatal("Invalid argument %s", ctx->argv[3]); |
99eef98b DF |
2546 | return; |
2547 | } | |
2548 | ||
2549 | vsctl_context_populate_cache(ctx); | |
2550 | ||
07ff77cc | 2551 | br = find_bridge(vsctl_ctx, ctx->argv[1], true); |
99eef98b DF |
2552 | if (br->parent) { |
2553 | br = br->parent; | |
2554 | } | |
2555 | ||
2bb0bea8 | 2556 | if (br->br_cfg && br->br_cfg->auto_attach && |
99eef98b DF |
2557 | br->br_cfg->auto_attach->key_mappings && |
2558 | br->br_cfg->auto_attach->value_mappings) { | |
2559 | size_t i; | |
2560 | ||
2561 | for (i = 0; i < br->br_cfg->auto_attach->n_mappings; i++) { | |
2562 | if (br->br_cfg->auto_attach->key_mappings[i] == isid && | |
2563 | br->br_cfg->auto_attach->value_mappings[i] == vlan) { | |
2564 | del_aa_mapping(br->br_cfg->auto_attach, isid, vlan); | |
2565 | break; | |
2566 | } | |
2567 | } | |
2568 | } | |
2569 | } | |
2570 | ||
2571 | static void | |
07ff77cc | 2572 | pre_aa_mapping(struct ctl_context *ctx) |
99eef98b DF |
2573 | { |
2574 | pre_get_info(ctx); | |
2575 | ||
d6f115f5 | 2576 | ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_auto_attach); |
99eef98b DF |
2577 | ovsdb_idl_add_column(ctx->idl, &ovsrec_autoattach_col_mappings); |
2578 | } | |
2579 | ||
2580 | static void | |
2581 | verify_auto_attach(struct ovsrec_bridge *bridge) | |
2582 | { | |
2583 | if (bridge) { | |
2584 | ovsrec_bridge_verify_auto_attach(bridge); | |
2585 | ||
2586 | if (bridge->auto_attach) { | |
2587 | ovsrec_autoattach_verify_mappings(bridge->auto_attach); | |
2588 | } | |
2589 | } | |
2590 | } | |
2591 | ||
2592 | static void | |
07ff77cc | 2593 | cmd_get_aa_mapping(struct ctl_context *ctx) |
99eef98b | 2594 | { |
07ff77cc | 2595 | struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); |
99eef98b DF |
2596 | struct vsctl_bridge *br; |
2597 | ||
2598 | vsctl_context_populate_cache(ctx); | |
2599 | ||
07ff77cc | 2600 | br = find_bridge(vsctl_ctx, ctx->argv[1], true); |
99eef98b DF |
2601 | if (br->parent) { |
2602 | br = br->parent; | |
2603 | } | |
2604 | ||
2605 | verify_auto_attach(br->br_cfg); | |
2606 | ||
2bb0bea8 | 2607 | if (br->br_cfg && br->br_cfg->auto_attach && |
99eef98b DF |
2608 | br->br_cfg->auto_attach->key_mappings && |
2609 | br->br_cfg->auto_attach->value_mappings) { | |
2610 | size_t i; | |
2611 | ||
2612 | for (i = 0; i < br->br_cfg->auto_attach->n_mappings; i++) { | |
2613 | ds_put_format(&ctx->output, "%"PRId64" %"PRId64"\n", | |
501b8053 BP |
2614 | br->br_cfg->auto_attach->key_mappings[i], |
2615 | br->br_cfg->auto_attach->value_mappings[i]); | |
99eef98b DF |
2616 | } |
2617 | } | |
2618 | } | |
2619 | ||
c75d1511 | 2620 | \f |
3f5b5f7b | 2621 | static const struct ctl_table_class tables[OVSREC_N_TABLES] = { |
15931827 | 2622 | [OVSREC_TABLE_BRIDGE].row_ids[0] = {&ovsrec_bridge_col_name, NULL, NULL}, |
ad83bfa6 | 2623 | |
3f5b5f7b | 2624 | [OVSREC_TABLE_CONTROLLER].row_ids[0] |
15931827 | 2625 | = {&ovsrec_bridge_col_name, NULL, &ovsrec_bridge_col_controller}, |
ad83bfa6 | 2626 | |
15931827 BP |
2627 | [OVSREC_TABLE_INTERFACE].row_ids[0] |
2628 | = {&ovsrec_interface_col_name, NULL, NULL}, | |
ad83bfa6 | 2629 | |
15931827 | 2630 | [OVSREC_TABLE_MIRROR].row_ids[0] = {&ovsrec_mirror_col_name, NULL, NULL}, |
ad83bfa6 | 2631 | |
15931827 BP |
2632 | [OVSREC_TABLE_MANAGER].row_ids[0] |
2633 | = {&ovsrec_manager_col_target, NULL, NULL}, | |
94db5407 | 2634 | |
3f5b5f7b | 2635 | [OVSREC_TABLE_NETFLOW].row_ids[0] |
15931827 | 2636 | = {&ovsrec_bridge_col_name, NULL, &ovsrec_bridge_col_netflow}, |
ad83bfa6 | 2637 | |
15931827 | 2638 | [OVSREC_TABLE_PORT].row_ids[0] = {&ovsrec_port_col_name, NULL, NULL}, |
ad83bfa6 | 2639 | |
3f5b5f7b | 2640 | [OVSREC_TABLE_QOS].row_ids[0] |
15931827 | 2641 | = {&ovsrec_port_col_name, NULL, &ovsrec_port_col_qos}, |
ad83bfa6 | 2642 | |
3f5b5f7b | 2643 | [OVSREC_TABLE_SFLOW].row_ids[0] |
15931827 | 2644 | = {&ovsrec_bridge_col_name, NULL, &ovsrec_bridge_col_sflow}, |
c1c9c9c4 | 2645 | |
3f5b5f7b | 2646 | [OVSREC_TABLE_FLOW_TABLE].row_ids[0] |
15931827 | 2647 | = {&ovsrec_flow_table_col_name, NULL, NULL}, |
ad83bfa6 | 2648 | |
a0b02897 | 2649 | [OVSREC_TABLE_IPFIX].row_ids[0] |
15931827 | 2650 | = {&ovsrec_bridge_col_name, NULL, &ovsrec_bridge_col_ipfix}, |
3f5b5f7b BP |
2651 | |
2652 | [OVSREC_TABLE_AUTOATTACH].row_ids[0] | |
15931827 | 2653 | = {&ovsrec_bridge_col_name, NULL, &ovsrec_bridge_col_auto_attach}, |
99eef98b | 2654 | |
3f5b5f7b | 2655 | [OVSREC_TABLE_FLOW_SAMPLE_COLLECTOR_SET].row_ids[0] |
15931827 | 2656 | = {&ovsrec_flow_sample_collector_set_col_id, NULL, NULL}, |
ad83bfa6 BP |
2657 | }; |
2658 | ||
1bc6ff29 | 2659 | static void |
07ff77cc | 2660 | post_db_reload_check_init(void) |
ad83bfa6 | 2661 | { |
07ff77cc | 2662 | n_neoteric_ifaces = 0; |
ad83bfa6 BP |
2663 | } |
2664 | ||
07ff77cc AW |
2665 | static void |
2666 | post_db_reload_expect_iface(const struct ovsrec_interface *iface) | |
ad83bfa6 | 2667 | { |
07ff77cc AW |
2668 | if (n_neoteric_ifaces >= allocated_neoteric_ifaces) { |
2669 | neoteric_ifaces = x2nrealloc(neoteric_ifaces, | |
2670 | &allocated_neoteric_ifaces, | |
2671 | sizeof *neoteric_ifaces); | |
ad83bfa6 | 2672 | } |
07ff77cc | 2673 | neoteric_ifaces[n_neoteric_ifaces++] = iface->header_.uuid; |
ad83bfa6 BP |
2674 | } |
2675 | ||
07ff77cc AW |
2676 | static void |
2677 | post_db_reload_do_checks(const struct vsctl_context *vsctl_ctx) | |
e5e12280 | 2678 | { |
feb38b6d | 2679 | bool print_error = false; |
07ff77cc | 2680 | size_t i; |
e5e12280 | 2681 | |
07ff77cc AW |
2682 | for (i = 0; i < n_neoteric_ifaces; i++) { |
2683 | const struct uuid *uuid; | |
ad83bfa6 | 2684 | |
07ff77cc AW |
2685 | uuid = ovsdb_idl_txn_get_insert_uuid(vsctl_ctx->base.txn, |
2686 | &neoteric_ifaces[i]); | |
2687 | if (uuid) { | |
2688 | const struct ovsrec_interface *iface; | |
ad83bfa6 | 2689 | |
07ff77cc AW |
2690 | iface = ovsrec_interface_get_for_uuid(vsctl_ctx->base.idl, uuid); |
2691 | if (iface && (!iface->ofport || *iface->ofport == -1)) { | |
feb38b6d DDP |
2692 | if (iface->error && *iface->error) { |
2693 | ovs_error(0, "Error detected while setting up '%s': %s. " | |
2694 | "See ovs-vswitchd log for details.", | |
2695 | iface->name, iface->error); | |
2696 | } else { | |
2697 | ovs_error(0, "Error detected while setting up '%s'. " | |
2698 | "See ovs-vswitchd log for details.", | |
2699 | iface->name); | |
2700 | } | |
2701 | print_error = true; | |
ad83bfa6 | 2702 | } |
ad83bfa6 BP |
2703 | } |
2704 | } | |
ad83bfa6 | 2705 | |
feb38b6d DDP |
2706 | if (print_error) { |
2707 | ovs_error(0, "The default log directory is \"%s\".", ovs_logdir()); | |
ad83bfa6 | 2708 | } |
ad83bfa6 BP |
2709 | } |
2710 | ||
07ff77cc AW |
2711 | \f |
2712 | static void | |
2713 | vsctl_context_init_command(struct vsctl_context *vsctl_ctx, | |
2714 | struct ctl_command *command) | |
ad83bfa6 | 2715 | { |
07ff77cc AW |
2716 | ctl_context_init_command(&vsctl_ctx->base, command); |
2717 | vsctl_ctx->verified_ports = false; | |
ad83bfa6 BP |
2718 | } |
2719 | ||
07ff77cc AW |
2720 | static void |
2721 | vsctl_context_init(struct vsctl_context *vsctl_ctx, | |
2722 | struct ctl_command *command, struct ovsdb_idl *idl, | |
2723 | struct ovsdb_idl_txn *txn, | |
2724 | const struct ovsrec_open_vswitch *ovs, | |
2725 | struct ovsdb_symbol_table *symtab) | |
ad83bfa6 | 2726 | { |
07ff77cc AW |
2727 | ctl_context_init(&vsctl_ctx->base, command, idl, txn, symtab, |
2728 | vsctl_context_invalidate_cache); | |
2729 | if (command) { | |
2730 | vsctl_ctx->verified_ports = false; | |
ad83bfa6 | 2731 | } |
07ff77cc AW |
2732 | vsctl_ctx->ovs = ovs; |
2733 | vsctl_ctx->cache_valid = false; | |
ad83bfa6 BP |
2734 | } |
2735 | ||
07ff77cc AW |
2736 | static void |
2737 | vsctl_context_done_command(struct vsctl_context *vsctl_ctx, | |
2738 | struct ctl_command *command) | |
aed133bf | 2739 | { |
07ff77cc | 2740 | ctl_context_done_command(&vsctl_ctx->base, command); |
aed133bf BP |
2741 | } |
2742 | ||
e5e12280 | 2743 | static void |
07ff77cc AW |
2744 | vsctl_context_done(struct vsctl_context *vsctl_ctx, |
2745 | struct ctl_command *command) | |
e5e12280 | 2746 | { |
07ff77cc | 2747 | ctl_context_done(&vsctl_ctx->base, command); |
e5e12280 BP |
2748 | } |
2749 | ||
07ff77cc AW |
2750 | static void |
2751 | run_prerequisites(struct ctl_command *commands, size_t n_commands, | |
2752 | struct ovsdb_idl *idl) | |
e89e5374 | 2753 | { |
07ff77cc | 2754 | struct ctl_command *c; |
e89e5374 | 2755 | |
07ff77cc AW |
2756 | ovsdb_idl_add_table(idl, &ovsrec_table_open_vswitch); |
2757 | if (wait_for_reload) { | |
2758 | ovsdb_idl_add_column(idl, &ovsrec_open_vswitch_col_cur_cfg); | |
ad83bfa6 | 2759 | } |
07ff77cc AW |
2760 | for (c = commands; c < &commands[n_commands]; c++) { |
2761 | if (c->syntax->prerequisites) { | |
2762 | struct vsctl_context vsctl_ctx; | |
ad83bfa6 | 2763 | |
07ff77cc AW |
2764 | ds_init(&c->output); |
2765 | c->table = NULL; | |
e89e5374 | 2766 | |
07ff77cc AW |
2767 | vsctl_context_init(&vsctl_ctx, c, idl, NULL, NULL, NULL); |
2768 | (c->syntax->prerequisites)(&vsctl_ctx.base); | |
675b152e JS |
2769 | if (vsctl_ctx.base.error) { |
2770 | ctl_fatal("%s", vsctl_ctx.base.error); | |
2771 | } | |
07ff77cc | 2772 | vsctl_context_done(&vsctl_ctx, c); |
1bc6ff29 | 2773 | |
07ff77cc AW |
2774 | ovs_assert(!c->output.string); |
2775 | ovs_assert(!c->table); | |
e89e5374 | 2776 | } |
ad83bfa6 BP |
2777 | } |
2778 | } | |
2779 | ||
48437177 WT |
2780 | static char * |
2781 | vsctl_parent_process_info(void) | |
2782 | { | |
2783 | #ifdef __linux__ | |
2784 | pid_t parent_pid; | |
48437177 | 2785 | struct ds s; |
48437177 WT |
2786 | |
2787 | parent_pid = getppid(); | |
9f4ecd65 KM |
2788 | ds_init(&s); |
2789 | ||
2790 | /* Retrive the command line of the parent process, except the init | |
2791 | * process since /proc/0 does not exist. */ | |
2792 | if (parent_pid) { | |
2793 | char *procfile; | |
2794 | FILE *f; | |
2795 | ||
2796 | procfile = xasprintf("/proc/%d/cmdline", parent_pid); | |
48437177 | 2797 | |
9f4ecd65 | 2798 | f = fopen(procfile, "r"); |
48437177 | 2799 | free(procfile); |
ed29f22b AZ |
2800 | if (f) { |
2801 | ds_get_line(&s, f); | |
2802 | fclose(f); | |
48437177 | 2803 | } |
9f4ecd65 KM |
2804 | } else { |
2805 | ds_put_cstr(&s, "init"); | |
48437177 | 2806 | } |
48437177 WT |
2807 | |
2808 | ds_put_format(&s, " (pid %d)", parent_pid); | |
48437177 WT |
2809 | return ds_steal_cstr(&s); |
2810 | #else | |
2811 | return NULL; | |
2812 | #endif | |
2813 | } | |
2814 | ||
2335ee93 | 2815 | static bool |
07ff77cc AW |
2816 | do_vsctl(const char *args, struct ctl_command *commands, size_t n_commands, |
2817 | struct ovsdb_idl *idl) | |
e5e12280 | 2818 | { |
07ff77cc AW |
2819 | struct ovsdb_idl_txn *txn; |
2820 | const struct ovsrec_open_vswitch *ovs; | |
2821 | enum ovsdb_idl_txn_status status; | |
2822 | struct ovsdb_symbol_table *symtab; | |
2823 | struct vsctl_context vsctl_ctx; | |
2824 | struct ctl_command *c; | |
2825 | struct shash_node *node; | |
2826 | int64_t next_cfg = 0; | |
48437177 | 2827 | char *ppid_info = NULL; |
e5e12280 | 2828 | |
07ff77cc AW |
2829 | txn = the_idl_txn = ovsdb_idl_txn_create(idl); |
2830 | if (dry_run) { | |
2831 | ovsdb_idl_txn_set_dry_run(txn); | |
e5e12280 BP |
2832 | } |
2833 | ||
48437177 WT |
2834 | ppid_info = vsctl_parent_process_info(); |
2835 | if (ppid_info) { | |
2836 | ovsdb_idl_txn_add_comment(txn, "ovs-vsctl (invoked by %s): %s", | |
2837 | ppid_info, args); | |
2838 | free(ppid_info); | |
2839 | } else { | |
2840 | ovsdb_idl_txn_add_comment(txn, "ovs-vsctl: %s", args); | |
2841 | } | |
341c4e59 | 2842 | |
07ff77cc AW |
2843 | ovs = ovsrec_open_vswitch_first(idl); |
2844 | if (!ovs) { | |
2845 | /* XXX add verification that table is empty */ | |
2846 | ovs = ovsrec_open_vswitch_insert(txn); | |
341c4e59 | 2847 | } |
e5e12280 | 2848 | |
07ff77cc AW |
2849 | if (wait_for_reload) { |
2850 | ovsdb_idl_txn_increment(txn, &ovs->header_, | |
de32cec7 | 2851 | &ovsrec_open_vswitch_col_next_cfg, false); |
b54e22e9 BP |
2852 | } |
2853 | ||
c3ccfe98 | 2854 | post_db_reload_check_init(); |
ce5a3e38 | 2855 | symtab = ovsdb_symbol_table_create(); |
87b23a01 BP |
2856 | for (c = commands; c < &commands[n_commands]; c++) { |
2857 | ds_init(&c->output); | |
e051b42c | 2858 | c->table = NULL; |
87b23a01 | 2859 | } |
07ff77cc | 2860 | vsctl_context_init(&vsctl_ctx, NULL, idl, txn, ovs, symtab); |
f8ff4bc4 | 2861 | for (c = commands; c < &commands[n_commands]; c++) { |
07ff77cc | 2862 | vsctl_context_init_command(&vsctl_ctx, c); |
ffd66ea9 | 2863 | if (c->syntax->run) { |
07ff77cc | 2864 | (c->syntax->run)(&vsctl_ctx.base); |
ffd66ea9 | 2865 | } |
675b152e JS |
2866 | if (vsctl_ctx.base.error) { |
2867 | ctl_fatal("%s", vsctl_ctx.base.error); | |
2868 | } | |
07ff77cc | 2869 | vsctl_context_done_command(&vsctl_ctx, c); |
87b23a01 | 2870 | |
07ff77cc AW |
2871 | if (vsctl_ctx.base.try_again) { |
2872 | vsctl_context_done(&vsctl_ctx, NULL); | |
87b23a01 BP |
2873 | goto try_again; |
2874 | } | |
c75d1511 | 2875 | } |
07ff77cc | 2876 | vsctl_context_done(&vsctl_ctx, NULL); |
c75d1511 | 2877 | |
0dc66db9 BP |
2878 | SHASH_FOR_EACH (node, &symtab->sh) { |
2879 | struct ovsdb_symbol *symbol = node->data; | |
2880 | if (!symbol->created) { | |
07ff77cc | 2881 | ctl_fatal("row id \"%s\" is referenced but never created (e.g. " |
0dc66db9 BP |
2882 | "with \"-- --id=%s create ...\")", |
2883 | node->name, node->name); | |
2884 | } | |
c5f341ab BP |
2885 | if (!symbol->strong_ref) { |
2886 | if (!symbol->weak_ref) { | |
2887 | VLOG_WARN("row id \"%s\" was created but no reference to it " | |
2888 | "was inserted, so it will not actually appear in " | |
2889 | "the database", node->name); | |
2890 | } else { | |
2891 | VLOG_WARN("row id \"%s\" was created but only a weak " | |
2892 | "reference to it was inserted, so it will not " | |
2893 | "actually appear in the database", node->name); | |
2894 | } | |
2895 | } | |
28a3b753 BP |
2896 | } |
2897 | ||
af96ccd2 | 2898 | status = ovsdb_idl_txn_commit_block(txn); |
b54e22e9 BP |
2899 | if (wait_for_reload && status == TXN_SUCCESS) { |
2900 | next_cfg = ovsdb_idl_txn_get_increment_new_value(txn); | |
2901 | } | |
8d49c47a BP |
2902 | if (status == TXN_UNCHANGED || status == TXN_SUCCESS) { |
2903 | for (c = commands; c < &commands[n_commands]; c++) { | |
2904 | if (c->syntax->postprocess) { | |
07ff77cc AW |
2905 | vsctl_context_init(&vsctl_ctx, c, idl, txn, ovs, symtab); |
2906 | (c->syntax->postprocess)(&vsctl_ctx.base); | |
675b152e JS |
2907 | if (vsctl_ctx.base.error) { |
2908 | ctl_fatal("%s", vsctl_ctx.base.error); | |
2909 | } | |
07ff77cc | 2910 | vsctl_context_done(&vsctl_ctx, c); |
8d49c47a | 2911 | } |
3da1c516 BP |
2912 | } |
2913 | } | |
c75d1511 BP |
2914 | |
2915 | switch (status) { | |
2096903b | 2916 | case TXN_UNCOMMITTED: |
c75d1511 | 2917 | case TXN_INCOMPLETE: |
428b2edd | 2918 | OVS_NOT_REACHED(); |
c75d1511 BP |
2919 | |
2920 | case TXN_ABORTED: | |
2921 | /* Should not happen--we never call ovsdb_idl_txn_abort(). */ | |
07ff77cc | 2922 | ctl_fatal("transaction aborted"); |
c75d1511 | 2923 | |
b54e22e9 | 2924 | case TXN_UNCHANGED: |
c75d1511 BP |
2925 | case TXN_SUCCESS: |
2926 | break; | |
2927 | ||
854a94d9 | 2928 | case TXN_TRY_AGAIN: |
87b23a01 | 2929 | goto try_again; |
c75d1511 BP |
2930 | |
2931 | case TXN_ERROR: | |
a9f55784 | 2932 | ctl_fatal("transaction error: %s", ovsdb_idl_txn_get_error(txn)); |
c75d1511 | 2933 | |
06b6d651 BP |
2934 | case TXN_NOT_LOCKED: |
2935 | /* Should not happen--we never call ovsdb_idl_set_lock(). */ | |
07ff77cc | 2936 | ctl_fatal("database not locked"); |
06b6d651 | 2937 | |
c75d1511 | 2938 | default: |
428b2edd | 2939 | OVS_NOT_REACHED(); |
c75d1511 BP |
2940 | } |
2941 | ||
87b23a01 BP |
2942 | ovsdb_symbol_table_destroy(symtab); |
2943 | ||
f8ff4bc4 BP |
2944 | for (c = commands; c < &commands[n_commands]; c++) { |
2945 | struct ds *ds = &c->output; | |
ce5a3e38 | 2946 | |
e051b42c BP |
2947 | if (c->table) { |
2948 | table_print(c->table, &table_style); | |
2949 | } else if (oneline) { | |
c75d1511 BP |
2950 | size_t j; |
2951 | ||
2952 | ds_chomp(ds, '\n'); | |
2953 | for (j = 0; j < ds->length; j++) { | |
2a022368 BP |
2954 | int ch = ds->string[j]; |
2955 | switch (ch) { | |
c75d1511 BP |
2956 | case '\n': |
2957 | fputs("\\n", stdout); | |
2958 | break; | |
2959 | ||
2960 | case '\\': | |
2961 | fputs("\\\\", stdout); | |
2962 | break; | |
2963 | ||
2964 | default: | |
2a022368 | 2965 | putchar(ch); |
c75d1511 BP |
2966 | } |
2967 | } | |
2968 | putchar('\n'); | |
2969 | } else { | |
2970 | fputs(ds_cstr(ds), stdout); | |
2971 | } | |
b86b43aa | 2972 | ds_destroy(&c->output); |
e051b42c BP |
2973 | table_destroy(c->table); |
2974 | free(c->table); | |
ce5a3e38 | 2975 | |
79f1cbe9 | 2976 | shash_destroy_free_data(&c->options); |
c75d1511 | 2977 | } |
b86b43aa | 2978 | free(commands); |
b54e22e9 BP |
2979 | |
2980 | if (wait_for_reload && status != TXN_UNCHANGED) { | |
705d7a39 AA |
2981 | /* Even, if --retry flag was not specified, ovs-vsctl still |
2982 | * has to retry to establish OVSDB connection, if wait_for_reload | |
2983 | * was set. Otherwise, ovs-vsctl would end up waiting forever | |
2984 | * until cur_cfg would be updated. */ | |
2985 | ovsdb_idl_enable_reconnect(idl); | |
b54e22e9 | 2986 | for (;;) { |
b54e22e9 BP |
2987 | ovsdb_idl_run(idl); |
2988 | OVSREC_OPEN_VSWITCH_FOR_EACH (ovs, idl) { | |
2989 | if (ovs->cur_cfg >= next_cfg) { | |
07ff77cc | 2990 | post_db_reload_do_checks(&vsctl_ctx); |
b54e22e9 BP |
2991 | goto done; |
2992 | } | |
2993 | } | |
2994 | ovsdb_idl_wait(idl); | |
2995 | poll_block(); | |
2996 | } | |
2997 | done: ; | |
2998 | } | |
c3ccfe98 | 2999 | ovsdb_idl_txn_destroy(txn); |
b86b43aa | 3000 | ovsdb_idl_destroy(idl); |
b54e22e9 | 3001 | |
2335ee93 | 3002 | return true; |
87b23a01 BP |
3003 | |
3004 | try_again: | |
3005 | /* Our transaction needs to be rerun, or a prerequisite was not met. Free | |
3006 | * resources and return so that the caller can try again. */ | |
6851589c BP |
3007 | ovsdb_idl_txn_abort(txn); |
3008 | ovsdb_idl_txn_destroy(txn); | |
3009 | the_idl_txn = NULL; | |
3010 | ||
87b23a01 BP |
3011 | ovsdb_symbol_table_destroy(symtab); |
3012 | for (c = commands; c < &commands[n_commands]; c++) { | |
3013 | ds_destroy(&c->output); | |
e051b42c BP |
3014 | table_destroy(c->table); |
3015 | free(c->table); | |
87b23a01 | 3016 | } |
2335ee93 | 3017 | return false; |
c75d1511 BP |
3018 | } |
3019 | ||
ce6f1d1f AZ |
3020 | /* Frees the current transaction and the underlying IDL and then calls |
3021 | * exit(status). | |
3022 | * | |
3023 | * Freeing the transaction and the IDL is not strictly necessary, but it makes | |
3024 | * for a clean memory leak report from valgrind in the normal case. That makes | |
3025 | * it easier to notice real memory leaks. */ | |
3026 | static void | |
3027 | vsctl_exit(int status) | |
3028 | { | |
3029 | if (the_idl_txn) { | |
3030 | ovsdb_idl_txn_abort(the_idl_txn); | |
3031 | ovsdb_idl_txn_destroy(the_idl_txn); | |
3032 | } | |
3033 | ovsdb_idl_destroy(the_idl); | |
3034 | exit(status); | |
3035 | } | |
3036 | ||
95e4a97a | 3037 | /* |
07ff77cc | 3038 | * Developers who add new commands to the 'struct ctl_command_syntax' must |
95e4a97a PA |
3039 | * define the 'arguments' member of the struct. The following keywords are |
3040 | * available for composing the argument format: | |
3041 | * | |
3042 | * TABLE RECORD BRIDGE PARENT PORT | |
3043 | * KEY VALUE ARG KEY=VALUE ?KEY=VALUE | |
3044 | * IFACE SYSIFACE COLUMN COLUMN?:KEY COLUMN?:KEY=VALUE | |
3045 | * MODE CA-CERT CERTIFICATE PRIVATE-KEY | |
3046 | * TARGET NEW-* (e.g. NEW-PORT) | |
3047 | * | |
3048 | * For argument types not listed above, just uses 'ARG' as place holder. | |
3049 | * | |
3050 | * Encloses the keyword with '[]' if it is optional. Appends '...' to | |
3051 | * keyword or enclosed keyword to indicate that the argument can be specified | |
3052 | * multiple times. | |
3053 | * | |
3054 | * */ | |
07ff77cc | 3055 | static const struct ctl_command_syntax vsctl_commands[] = { |
f8ff4bc4 | 3056 | /* Open vSwitch commands. */ |
95e4a97a | 3057 | {"init", 0, 0, "", NULL, cmd_init, NULL, "", RW}, |
f8ff4bc4 BP |
3058 | |
3059 | /* Bridge commands. */ | |
95e4a97a PA |
3060 | {"add-br", 1, 3, "NEW-BRIDGE [PARENT] [NEW-VLAN]", pre_get_info, |
3061 | cmd_add_br, NULL, "--may-exist", RW}, | |
3062 | {"del-br", 1, 1, "BRIDGE", pre_get_info, cmd_del_br, | |
3063 | NULL, "--if-exists", RW}, | |
3064 | {"list-br", 0, 0, "", pre_get_info, cmd_list_br, NULL, "--real,--fake", | |
3065 | RO}, | |
3066 | {"br-exists", 1, 1, "BRIDGE", pre_get_info, cmd_br_exists, NULL, "", RO}, | |
3067 | {"br-to-vlan", 1, 1, "BRIDGE", pre_get_info, cmd_br_to_vlan, NULL, "", | |
3068 | RO}, | |
3069 | {"br-to-parent", 1, 1, "BRIDGE", pre_get_info, cmd_br_to_parent, NULL, | |
3070 | "", RO}, | |
3071 | {"br-set-external-id", 2, 3, "BRIDGE KEY [VALUE]", | |
3072 | pre_cmd_br_set_external_id, cmd_br_set_external_id, NULL, "", RW}, | |
3073 | {"br-get-external-id", 1, 2, "BRIDGE [KEY]", pre_cmd_br_get_external_id, | |
e5e12280 | 3074 | cmd_br_get_external_id, NULL, "", RO}, |
f8ff4bc4 BP |
3075 | |
3076 | /* Port commands. */ | |
95e4a97a PA |
3077 | {"list-ports", 1, 1, "BRIDGE", pre_get_info, cmd_list_ports, NULL, "", |
3078 | RO}, | |
3079 | {"add-port", 2, INT_MAX, "BRIDGE NEW-PORT [COLUMN[:KEY]=VALUE]...", | |
3080 | pre_get_info, cmd_add_port, NULL, "--may-exist", RW}, | |
95e4a97a | 3081 | {"del-port", 1, 2, "[BRIDGE] PORT|IFACE", pre_get_info, cmd_del_port, NULL, |
e5e12280 | 3082 | "--if-exists,--with-iface", RW}, |
95e4a97a | 3083 | {"port-to-br", 1, 1, "PORT", pre_get_info, cmd_port_to_br, NULL, "", RO}, |
f8ff4bc4 | 3084 | |
ec5ef1cf BP |
3085 | /* Bond commands. */ |
3086 | {"add-bond", 4, INT_MAX, | |
3087 | "BRIDGE BOND IFACE... [COLUMN[:KEY]=VALUE]...", pre_get_info, | |
3088 | cmd_add_bond, NULL, "--may-exist,--fake-iface", RW}, | |
3089 | {"add-bond-iface", 2, 2, "BOND IFACE", pre_get_info, cmd_add_bond_iface, | |
3090 | NULL, "--may-exist", RW}, | |
3091 | {"del-bond-iface", 1, 2, "[BOND] IFACE", pre_get_info, cmd_del_bond_iface, | |
3092 | NULL, "--if-exists", RW}, | |
3093 | ||
f8ff4bc4 | 3094 | /* Interface commands. */ |
95e4a97a PA |
3095 | {"list-ifaces", 1, 1, "BRIDGE", pre_get_info, cmd_list_ifaces, NULL, "", |
3096 | RO}, | |
3097 | {"iface-to-br", 1, 1, "IFACE", pre_get_info, cmd_iface_to_br, NULL, "", | |
3098 | RO}, | |
f8ff4bc4 BP |
3099 | |
3100 | /* Controller commands. */ | |
95e4a97a PA |
3101 | {"get-controller", 1, 1, "BRIDGE", pre_controller, cmd_get_controller, |
3102 | NULL, "", RO}, | |
3103 | {"del-controller", 1, 1, "BRIDGE", pre_controller, cmd_del_controller, | |
3104 | NULL, "", RW}, | |
3105 | {"set-controller", 1, INT_MAX, "BRIDGE TARGET...", pre_controller, | |
3ffed5cb | 3106 | cmd_set_controller, NULL, "--inactivity-probe=", RW}, |
95e4a97a PA |
3107 | {"get-fail-mode", 1, 1, "BRIDGE", pre_get_info, cmd_get_fail_mode, NULL, |
3108 | "", RO}, | |
3109 | {"del-fail-mode", 1, 1, "BRIDGE", pre_get_info, cmd_del_fail_mode, NULL, | |
4e3e7ff9 | 3110 | "", RW}, |
95e4a97a PA |
3111 | {"set-fail-mode", 2, 2, "BRIDGE MODE", pre_get_info, cmd_set_fail_mode, |
3112 | NULL, "", RW}, | |
f8ff4bc4 | 3113 | |
24b8b259 | 3114 | /* Manager commands. */ |
95e4a97a PA |
3115 | {"get-manager", 0, 0, "", pre_manager, cmd_get_manager, NULL, "", RO}, |
3116 | {"del-manager", 0, 0, "", pre_manager, cmd_del_manager, NULL, "", RW}, | |
3117 | {"set-manager", 1, INT_MAX, "TARGET...", pre_manager, cmd_set_manager, | |
3ffed5cb | 3118 | NULL, "--inactivity-probe=", RW}, |
24b8b259 | 3119 | |
f8ff4bc4 | 3120 | /* SSL commands. */ |
95e4a97a PA |
3121 | {"get-ssl", 0, 0, "", pre_cmd_get_ssl, cmd_get_ssl, NULL, "", RO}, |
3122 | {"del-ssl", 0, 0, "", pre_cmd_del_ssl, cmd_del_ssl, NULL, "", RW}, | |
3123 | {"set-ssl", 3, 3, "PRIVATE-KEY CERTIFICATE CA-CERT", pre_cmd_set_ssl, | |
3124 | cmd_set_ssl, NULL, "--bootstrap", RW}, | |
f8ff4bc4 | 3125 | |
99eef98b | 3126 | /* Auto Attach commands. */ |
d6f115f5 | 3127 | {"add-aa-mapping", 3, 3, "BRIDGE ARG ARG", pre_aa_mapping, cmd_add_aa_mapping, |
95e4a97a PA |
3128 | NULL, "", RW}, |
3129 | {"del-aa-mapping", 3, 3, "BRIDGE ARG ARG", pre_aa_mapping, cmd_del_aa_mapping, | |
3130 | NULL, "", RW}, | |
3131 | {"get-aa-mapping", 1, 1, "BRIDGE", pre_aa_mapping, cmd_get_aa_mapping, | |
3132 | NULL, "", RO}, | |
99eef98b | 3133 | |
18ee958b | 3134 | /* Switch commands. */ |
95e4a97a | 3135 | {"emer-reset", 0, 0, "", pre_cmd_emer_reset, cmd_emer_reset, NULL, "", RW}, |
18ee958b | 3136 | |
45339539 WT |
3137 | /* Zone and CT Timeout Policy commands. */ |
3138 | {"add-zone-tp", 3, INT_MAX, "", pre_get_zone, cmd_add_zone_tp, NULL, | |
3139 | "--may-exist", RW}, | |
3140 | {"del-zone-tp", 2, 2, "", pre_get_zone, cmd_del_zone_tp, NULL, | |
3141 | "--if-exists", RW}, | |
3142 | {"list-zone-tp", 1, 1, "", pre_get_zone, cmd_list_zone_tp, NULL, "", RO}, | |
3143 | ||
27501802 WT |
3144 | /* Datapath capabilities. */ |
3145 | {"list-dp-cap", 1, 1, "", pre_get_dp_cap, cmd_list_dp_cap, NULL, "", RO}, | |
3146 | ||
95e4a97a | 3147 | {NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, RO}, |
f8ff4bc4 | 3148 | }; |
5d9cb63c | 3149 | |
07ff77cc AW |
3150 | /* Registers vsctl and common db commands. */ |
3151 | static void | |
3152 | vsctl_cmd_init(void) | |
3815d6c2 | 3153 | { |
8519ea87 MM |
3154 | ctl_init(&ovsrec_idl_class, ovsrec_table_classes, tables, cmd_show_tables, |
3155 | vsctl_exit); | |
07ff77cc | 3156 | ctl_register_commands(vsctl_commands); |
3815d6c2 | 3157 | } |