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