Branch data Line data Source code
1 : : /*
2 : : * Licensed under the Apache License, Version 2.0 (the "License");
3 : : * you may not use this file except in compliance with the License.
4 : : * You may obtain a copy of the License at:
5 : : *
6 : : * http://www.apache.org/licenses/LICENSE-2.0
7 : : *
8 : : * Unless required by applicable law or agreed to in writing, software
9 : : * distributed under the License is distributed on an "AS IS" BASIS,
10 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 : : * See the License for the specific language governing permissions and
12 : : * limitations under the License.
13 : : */
14 : :
15 : : #include <config.h>
16 : :
17 : : #include <getopt.h>
18 : : #include <inttypes.h>
19 : : #include <stdlib.h>
20 : : #include <stdio.h>
21 : :
22 : : #include "command-line.h"
23 : : #include "db-ctl-base.h"
24 : : #include "dirs.h"
25 : : #include "fatal-signal.h"
26 : : #include "openvswitch/json.h"
27 : : #include "ovn/lib/ovn-nb-idl.h"
28 : : #include "ovn/lib/ovn-util.h"
29 : : #include "packets.h"
30 : : #include "poll-loop.h"
31 : : #include "process.h"
32 : : #include "smap.h"
33 : : #include "sset.h"
34 : : #include "stream.h"
35 : : #include "stream-ssl.h"
36 : : #include "svec.h"
37 : : #include "table.h"
38 : : #include "timeval.h"
39 : : #include "util.h"
40 : : #include "openvswitch/vlog.h"
41 : :
42 : 1786 : VLOG_DEFINE_THIS_MODULE(nbctl);
43 : :
44 : : /* --db: The database server to contact. */
45 : : static const char *db;
46 : :
47 : : /* --oneline: Write each command's output as a single line? */
48 : : static bool oneline;
49 : :
50 : : /* --dry-run: Do not commit any changes. */
51 : : static bool dry_run;
52 : :
53 : : /* --wait=TYPE: Wait for configuration change to take effect? */
54 : : enum nbctl_wait_type {
55 : : NBCTL_WAIT_NONE, /* Do not wait. */
56 : : NBCTL_WAIT_SB, /* Wait for southbound database updates. */
57 : : NBCTL_WAIT_HV /* Wait for hypervisors to catch up. */
58 : : };
59 : : static enum nbctl_wait_type wait_type = NBCTL_WAIT_NONE;
60 : :
61 : : /* Should we wait (if specified by 'wait_type') even if the commands don't
62 : : * change the database at all? */
63 : : static bool force_wait = false;
64 : :
65 : : /* --timeout: Time to wait for a connection to 'db'. */
66 : : static int timeout;
67 : :
68 : : /* Format for table output. */
69 : : static struct table_style table_style = TABLE_STYLE_DEFAULT;
70 : :
71 : : /* The IDL we're using and the current transaction, if any.
72 : : * This is for use by nbctl_exit() only, to allow it to clean up.
73 : : * Other code should use its context arguments. */
74 : : static struct ovsdb_idl *the_idl;
75 : : static struct ovsdb_idl_txn *the_idl_txn;
76 : : OVS_NO_RETURN static void nbctl_exit(int status);
77 : :
78 : : static void nbctl_cmd_init(void);
79 : : OVS_NO_RETURN static void usage(void);
80 : : static void parse_options(int argc, char *argv[], struct shash *local_options);
81 : : static void run_prerequisites(struct ctl_command[], size_t n_commands,
82 : : struct ovsdb_idl *);
83 : : static bool do_nbctl(const char *args, struct ctl_command *, size_t n,
84 : : struct ovsdb_idl *);
85 : : static const struct nbrec_dhcp_options *dhcp_options_get(
86 : : struct ctl_context *ctx, const char *id, bool must_exist);
87 : :
88 : : int
89 : 893 : main(int argc, char *argv[])
90 : : {
91 : : struct ovsdb_idl *idl;
92 : : struct ctl_command *commands;
93 : : struct shash local_options;
94 : : unsigned int seqno;
95 : : size_t n_commands;
96 : : char *args;
97 : :
98 : 893 : set_program_name(argv[0]);
99 : 893 : fatal_ignore_sigpipe();
100 : 893 : vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
101 : 893 : vlog_set_levels_from_string_assert("reconnect:warn");
102 : 893 : nbrec_init();
103 : :
104 : 893 : nbctl_cmd_init();
105 : :
106 : : /* Log our arguments. This is often valuable for debugging systems. */
107 : 893 : args = process_escape_args(argv);
108 [ + + ][ + + ]: 893 : VLOG(ctl_might_write_to_db(argv) ? VLL_INFO : VLL_DBG,
109 : : "Called as %s", args);
110 : :
111 : : /* Parse command line. */
112 : 893 : shash_init(&local_options);
113 : 893 : parse_options(argc, argv, &local_options);
114 : 893 : commands = ctl_parse_commands(argc - optind, argv + optind, &local_options,
115 : : &n_commands);
116 : :
117 [ - + ]: 893 : if (timeout) {
118 : 0 : time_alarm(timeout);
119 : : }
120 : :
121 : : /* Initialize IDL. */
122 : 893 : idl = the_idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false);
123 : 893 : run_prerequisites(commands, n_commands, idl);
124 : :
125 : : /* Execute the commands.
126 : : *
127 : : * 'seqno' is the database sequence number for which we last tried to
128 : : * execute our transaction. There's no point in trying to commit more than
129 : : * once for any given sequence number, because if the transaction fails
130 : : * it's because the database changed and we need to obtain an up-to-date
131 : : * view of the database before we try the transaction again. */
132 : 893 : seqno = ovsdb_idl_get_seqno(idl);
133 : : for (;;) {
134 : 2321 : ovsdb_idl_run(idl);
135 [ - + ]: 2321 : if (!ovsdb_idl_is_alive(idl)) {
136 : 0 : int retval = ovsdb_idl_get_last_error(idl);
137 : 0 : ctl_fatal("%s: database connection failed (%s)",
138 : : db, ovs_retval_to_string(retval));
139 : : }
140 : :
141 [ + + ]: 2321 : if (seqno != ovsdb_idl_get_seqno(idl)) {
142 : 893 : seqno = ovsdb_idl_get_seqno(idl);
143 [ + - ]: 893 : if (do_nbctl(args, commands, n_commands, idl)) {
144 : 864 : free(args);
145 : 864 : exit(EXIT_SUCCESS);
146 : : }
147 : : }
148 : :
149 [ + - ]: 1428 : if (seqno == ovsdb_idl_get_seqno(idl)) {
150 : 1428 : ovsdb_idl_wait(idl);
151 : 1428 : poll_block();
152 : : }
153 : 1428 : }
154 : : }
155 : :
156 : : static void
157 : 893 : parse_options(int argc, char *argv[], struct shash *local_options)
158 : : {
159 : : enum {
160 : : OPT_DB = UCHAR_MAX + 1,
161 : : OPT_NO_SYSLOG,
162 : : OPT_NO_WAIT,
163 : : OPT_WAIT,
164 : : OPT_DRY_RUN,
165 : : OPT_ONELINE,
166 : : OPT_LOCAL,
167 : : OPT_COMMANDS,
168 : : OPT_OPTIONS,
169 : : VLOG_OPTION_ENUMS,
170 : : TABLE_OPTION_ENUMS
171 : : };
172 : : static const struct option global_long_options[] = {
173 : : {"db", required_argument, NULL, OPT_DB},
174 : : {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG},
175 : : {"no-wait", no_argument, NULL, OPT_NO_WAIT},
176 : : {"wait", required_argument, NULL, OPT_WAIT},
177 : : {"dry-run", no_argument, NULL, OPT_DRY_RUN},
178 : : {"oneline", no_argument, NULL, OPT_ONELINE},
179 : : {"timeout", required_argument, NULL, 't'},
180 : : {"help", no_argument, NULL, 'h'},
181 : : {"commands", no_argument, NULL, OPT_COMMANDS},
182 : : {"options", no_argument, NULL, OPT_OPTIONS},
183 : : {"version", no_argument, NULL, 'V'},
184 : : VLOG_LONG_OPTIONS,
185 : : STREAM_SSL_LONG_OPTIONS,
186 : : TABLE_LONG_OPTIONS,
187 : : {NULL, 0, NULL, 0},
188 : : };
189 : 893 : const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1;
190 : : char *tmp, *short_options;
191 : :
192 : : struct option *options;
193 : : size_t allocated_options;
194 : : size_t n_options;
195 : : size_t i;
196 : :
197 : 893 : tmp = ovs_cmdl_long_options_to_short_options(global_long_options);
198 : 893 : short_options = xasprintf("+%s", tmp);
199 : 893 : free(tmp);
200 : :
201 : : /* We want to parse both global and command-specific options here, but
202 : : * getopt_long() isn't too convenient for the job. We copy our global
203 : : * options into a dynamic array, then append all of the command-specific
204 : : * options. */
205 : 893 : options = xmemdup(global_long_options, sizeof global_long_options);
206 : 893 : allocated_options = ARRAY_SIZE(global_long_options);
207 : 893 : n_options = n_global_long_options;
208 : 893 : ctl_add_cmd_options(&options, &n_options, &allocated_options, OPT_LOCAL);
209 : 893 : table_style.format = TF_LIST;
210 : :
211 : : for (;;) {
212 : : int idx;
213 : : int c;
214 : :
215 : 941 : c = getopt_long(argc, argv, short_options, options, &idx);
216 [ + + ]: 941 : if (c == -1) {
217 : 893 : break;
218 : : }
219 : :
220 [ - - - - : 48 : switch (c) {
+ - + - -
- - - - -
- - - - -
- - - - -
- - ]
221 : : case OPT_DB:
222 : 0 : db = optarg;
223 : 0 : break;
224 : :
225 : : case OPT_ONELINE:
226 : 0 : oneline = true;
227 : 0 : break;
228 : :
229 : : case OPT_NO_SYSLOG:
230 : 0 : vlog_set_levels(&this_module, VLF_SYSLOG, VLL_WARN);
231 : 0 : break;
232 : :
233 : : case OPT_NO_WAIT:
234 : 0 : wait_type = NBCTL_WAIT_NONE;
235 : 0 : break;
236 : :
237 : : case OPT_WAIT:
238 [ - + ]: 14 : if (!strcmp(optarg, "none")) {
239 : 0 : wait_type = NBCTL_WAIT_NONE;
240 [ + - ]: 14 : } else if (!strcmp(optarg, "sb")) {
241 : 14 : wait_type = NBCTL_WAIT_SB;
242 [ # # ]: 0 : } else if (!strcmp(optarg, "hv")) {
243 : 0 : wait_type = NBCTL_WAIT_HV;
244 : : } else {
245 : 0 : ctl_fatal("argument to --wait must be "
246 : : "\"none\", \"sb\", or \"hv\"");
247 : : }
248 : 14 : break;
249 : :
250 : : case OPT_DRY_RUN:
251 : 0 : dry_run = true;
252 : 0 : break;
253 : :
254 : : case OPT_LOCAL:
255 [ - + ]: 34 : if (shash_find(local_options, options[idx].name)) {
256 : 0 : ctl_fatal("'%s' option specified multiple times",
257 : 0 : options[idx].name);
258 : : }
259 : 34 : shash_add_nocopy(local_options,
260 : 34 : xasprintf("--%s", options[idx].name),
261 : 34 : nullable_xstrdup(optarg));
262 : 34 : break;
263 : :
264 : : case 'h':
265 : 0 : usage();
266 : : exit(EXIT_SUCCESS);
267 : :
268 : : case OPT_COMMANDS:
269 : 0 : ctl_print_commands();
270 : :
271 : : case OPT_OPTIONS:
272 : 0 : ctl_print_options(global_long_options);
273 : :
274 : : case 'V':
275 : 0 : ovs_print_version(0, 0);
276 : 0 : printf("DB Schema %s\n", nbrec_get_db_version());
277 : 0 : exit(EXIT_SUCCESS);
278 : :
279 : : case 't':
280 : 0 : timeout = strtoul(optarg, NULL, 10);
281 [ # # ]: 0 : if (timeout < 0) {
282 : 0 : ctl_fatal("value %s on -t or --timeout is invalid", optarg);
283 : : }
284 : 0 : break;
285 : :
286 : 0 : VLOG_OPTION_HANDLERS
287 : 0 : TABLE_OPTION_HANDLERS(&table_style)
288 : 0 : STREAM_SSL_OPTION_HANDLERS
289 : :
290 : : case '?':
291 : 0 : exit(EXIT_FAILURE);
292 : :
293 : : default:
294 : 0 : abort();
295 : : }
296 : 48 : }
297 : 893 : free(short_options);
298 : :
299 [ + - ]: 893 : if (!db) {
300 : 893 : db = default_nb_db();
301 : : }
302 : :
303 [ + + ]: 7144 : for (i = n_global_long_options; options[i].name; i++) {
304 : 6251 : free(CONST_CAST(char *, options[i].name));
305 : : }
306 : 893 : free(options);
307 : 893 : }
308 : :
309 : : static void
310 : 0 : usage(void)
311 : : {
312 : 0 : printf("\
313 : : %s: OVN northbound DB management utility\n\
314 : : usage: %s [OPTIONS] COMMAND [ARG...]\n\
315 : : \n\
316 : : General commands:\n\
317 : : init initialize the database\n\
318 : : show print overview of database contents\n\
319 : : show SWITCH print overview of database contents for SWITCH\n\
320 : : show ROUTER print overview of database contents for ROUTER\n\
321 : : \n\
322 : : Logical switch commands:\n\
323 : : ls-add [SWITCH] create a logical switch named SWITCH\n\
324 : : ls-del SWITCH delete SWITCH and all its ports\n\
325 : : ls-list print the names of all logical switches\n\
326 : : \n\
327 : : ACL commands:\n\
328 : : acl-add SWITCH DIRECTION PRIORITY MATCH ACTION [log]\n\
329 : : add an ACL to SWITCH\n\
330 : : acl-del SWITCH [DIRECTION [PRIORITY MATCH]]\n\
331 : : remove ACLs from SWITCH\n\
332 : : acl-list SWITCH print ACLs for SWITCH\n\
333 : : \n\
334 : : Logical switch port commands:\n\
335 : : lsp-add SWITCH PORT add logical port PORT on SWITCH\n\
336 : : lsp-add SWITCH PORT PARENT TAG\n\
337 : : add logical port PORT on SWITCH with PARENT\n\
338 : : on TAG\n\
339 : : lsp-del PORT delete PORT from its attached switch\n\
340 : : lsp-list SWITCH print the names of all logical ports on SWITCH\n\
341 : : lsp-get-parent PORT get the parent of PORT if set\n\
342 : : lsp-get-tag PORT get the PORT's tag if set\n\
343 : : lsp-set-addresses PORT [ADDRESS]...\n\
344 : : set MAC or MAC+IP addresses for PORT.\n\
345 : : lsp-get-addresses PORT get a list of MAC or MAC+IP addresses on PORT\n\
346 : : lsp-set-port-security PORT [ADDRS]...\n\
347 : : set port security addresses for PORT.\n\
348 : : lsp-get-port-security PORT get PORT's port security addresses\n\
349 : : lsp-get-up PORT get state of PORT ('up' or 'down')\n\
350 : : lsp-set-enabled PORT STATE\n\
351 : : set administrative state PORT\n\
352 : : ('enabled' or 'disabled')\n\
353 : : lsp-get-enabled PORT get administrative state PORT\n\
354 : : ('enabled' or 'disabled')\n\
355 : : lsp-set-type PORT TYPE set the type for PORT\n\
356 : : lsp-get-type PORT get the type for PORT\n\
357 : : lsp-set-options PORT KEY=VALUE [KEY=VALUE]...\n\
358 : : set options related to the type of PORT\n\
359 : : lsp-get-options PORT get the type specific options for PORT\n\
360 : : lsp-set-dhcpv4-options PORT [DHCP_OPTIONS_UUID]\n\
361 : : set dhcpv4 options for PORT\n\
362 : : lsp-get-dhcpv4-options PORT get the dhcpv4 options for PORT\n\
363 : : \n\
364 : : Logical router commands:\n\
365 : : lr-add [ROUTER] create a logical router named ROUTER\n\
366 : : lr-del ROUTER delete ROUTER and all its ports\n\
367 : : lr-list print the names of all logical routers\n\
368 : : \n\
369 : : Logical router port commands:\n\
370 : : lrp-add ROUTER PORT MAC NETWORK... [peer=PEER]\n\
371 : : add logical port PORT on ROUTER\n\
372 : : lrp-del PORT delete PORT from its attached router\n\
373 : : lrp-list ROUTER print the names of all ports on ROUTER\n\
374 : : lrp-set-enabled PORT STATE\n\
375 : : set administrative state PORT\n\
376 : : ('enabled' or 'disabled')\n\
377 : : lrp-get-enabled PORT get administrative state PORT\n\
378 : : ('enabled' or 'disabled')\n\
379 : : \n\
380 : : Route commands:\n\
381 : : lr-route-add ROUTER PREFIX NEXTHOP [PORT]\n\
382 : : add a route to ROUTER\n\
383 : : lr-route-del ROUTER [PREFIX]\n\
384 : : remove routes from ROUTER\n\
385 : : lr-route-list ROUTER print routes for ROUTER\n\
386 : : \n\
387 : : \n\
388 : : DHCP Options commands:\n\
389 : : dhcp-options-create CIDR [EXTERNAL_IDS]\n\
390 : : create a DHCP options row with CIDR\n\
391 : : dhcp-options-del DHCP_OPTIONS_UUID\n\
392 : : delete DHCP_OPTIONS_UUID\n\
393 : : dhcp-options-list \n\
394 : : lists the DHCP_Options rows\n\
395 : : dhcp-options-set-options DHCP_OPTIONS_UUID KEY=VALUE [KEY=VALUE]...\n\
396 : : set DHCP options for DHCP_OPTIONS_UUID\n\
397 : : dhcp-options-get-options DHCO_OPTIONS_UUID \n\
398 : : displays the DHCP options for DHCP_OPTIONS_UUID\n\
399 : : \n\
400 : : %s\
401 : : \n\
402 : : Synchronization command (use with --wait=sb|hv):\n\
403 : : sync wait even for earlier changes to take effect\n\
404 : : \n\
405 : : Options:\n\
406 : : --db=DATABASE connect to DATABASE\n\
407 : : (default: %s)\n\
408 : : --no-wait, --wait=none do not wait for OVN reconfiguration (default)\n\
409 : : --wait=sb wait for southbound database update\n\
410 : : --wait=hv wait for all chassis to catch up\n\
411 : : -t, --timeout=SECS wait at most SECS seconds\n\
412 : : --dry-run do not commit changes to database\n\
413 : : --oneline print exactly one line of output per command\n",
414 : : program_name, program_name, ctl_get_db_cmd_usage(),
415 : : default_nb_db());
416 : 0 : vlog_usage();
417 : 0 : printf("\
418 : : --no-syslog equivalent to --verbose=nbctl:syslog:warn\n");
419 : 0 : printf("\n\
420 : : Other options:\n\
421 : : -h, --help display this help message\n\
422 : : -V, --version display version information\n");
423 : 0 : exit(EXIT_SUCCESS);
424 : : }
425 : :
426 : :
427 : : /* Find a logical router given its id. */
428 : : static const struct nbrec_logical_router *
429 : 136 : lr_by_name_or_uuid(struct ctl_context *ctx, const char *id,
430 : : bool must_exist)
431 : : {
432 : 136 : const struct nbrec_logical_router *lr = NULL;
433 : 136 : bool is_uuid = false;
434 : : struct uuid lr_uuid;
435 : :
436 [ - + ]: 136 : if (uuid_from_string(&lr_uuid, id)) {
437 : 0 : is_uuid = true;
438 : 0 : lr = nbrec_logical_router_get_for_uuid(ctx->idl, &lr_uuid);
439 : : }
440 : :
441 [ + - ]: 136 : if (!lr) {
442 : : const struct nbrec_logical_router *iter;
443 : :
444 [ + + ]: 352 : NBREC_LOGICAL_ROUTER_FOR_EACH(iter, ctx->idl) {
445 [ + + ]: 217 : if (strcmp(iter->name, id)) {
446 : 86 : continue;
447 : : }
448 [ + + ]: 131 : if (lr) {
449 : 1 : ctl_fatal("Multiple logical routers named '%s'. "
450 : : "Use a UUID.", id);
451 : : }
452 : 130 : lr = iter;
453 : : }
454 : : }
455 : :
456 [ + + ][ + + ]: 135 : if (!lr && must_exist) {
457 [ - + ]: 1 : ctl_fatal("%s: router %s not found", id, is_uuid ? "UUID" : "name");
458 : : }
459 : :
460 : 134 : return lr;
461 : : }
462 : :
463 : : static const struct nbrec_logical_switch *
464 : 295 : ls_by_name_or_uuid(struct ctl_context *ctx, const char *id, bool must_exist)
465 : : {
466 : 295 : const struct nbrec_logical_switch *ls = NULL;
467 : :
468 : : struct uuid ls_uuid;
469 : 295 : bool is_uuid = uuid_from_string(&ls_uuid, id);
470 [ - + ]: 295 : if (is_uuid) {
471 : 0 : ls = nbrec_logical_switch_get_for_uuid(ctx->idl, &ls_uuid);
472 : : }
473 : :
474 [ + - ]: 295 : if (!ls) {
475 : : const struct nbrec_logical_switch *iter;
476 : :
477 [ + + ]: 867 : NBREC_LOGICAL_SWITCH_FOR_EACH(iter, ctx->idl) {
478 [ + + ]: 573 : if (strcmp(iter->name, id)) {
479 : 284 : continue;
480 : : }
481 [ + + ]: 289 : if (ls) {
482 : 1 : ctl_fatal("Multiple logical switches named '%s'. "
483 : : "Use a UUID.", id);
484 : : }
485 : 288 : ls = iter;
486 : : }
487 : : }
488 : :
489 [ + + ][ + + ]: 294 : if (!ls && must_exist) {
490 [ - + ]: 1 : ctl_fatal("%s: switch %s not found", id, is_uuid ? "UUID" : "name");
491 : : }
492 : :
493 : 293 : return ls;
494 : : }
495 : :
496 : : /* Given pointer to logical router, this routine prints the router
497 : : * information. */
498 : : static void
499 : 17 : print_lr(const struct nbrec_logical_router *lr, struct ds *s)
500 : : {
501 : 17 : ds_put_format(s, " router "UUID_FMT" (%s)\n",
502 : 51 : UUID_ARGS(&lr->header_.uuid), lr->name);
503 : :
504 [ + + ]: 46 : for (size_t i = 0; i < lr->n_ports; i++) {
505 : 29 : const struct nbrec_logical_router_port *lrp = lr->ports[i];
506 : 29 : ds_put_format(s, " port %s\n", lrp->name);
507 [ + - ]: 29 : if (lrp->mac) {
508 : 29 : ds_put_cstr(s, " mac: ");
509 : 29 : ds_put_format(s, "\"%s\"\n", lrp->mac);
510 : : }
511 [ + - ]: 29 : if (lrp->n_networks) {
512 : 29 : ds_put_cstr(s, " networks: [");
513 [ + + ]: 59 : for (size_t j = 0; j < lrp->n_networks; j++) {
514 [ + + ]: 30 : ds_put_format(s, "%s\"%s\"",
515 : : j == 0 ? "" : ", ",
516 : 30 : lrp->networks[j]);
517 : : }
518 : 29 : ds_put_cstr(s, "]\n");
519 : : }
520 : : }
521 : 17 : }
522 : :
523 : : static void
524 : 33 : print_ls(const struct nbrec_logical_switch *ls, struct ds *s)
525 : : {
526 : 33 : ds_put_format(s, " switch "UUID_FMT" (%s)\n",
527 : 99 : UUID_ARGS(&ls->header_.uuid), ls->name);
528 : :
529 [ + + ]: 114 : for (size_t i = 0; i < ls->n_ports; i++) {
530 : 81 : const struct nbrec_logical_switch_port *lsp = ls->ports[i];
531 : :
532 : 81 : ds_put_format(s, " port %s\n", lsp->name);
533 [ + + ]: 81 : if (lsp->parent_name) {
534 : 1 : ds_put_format(s, " parent: %s\n", lsp->parent_name);
535 : : }
536 [ + + ]: 81 : if (lsp->n_tag) {
537 : 1 : ds_put_format(s, " tag: %"PRIu64"\n", lsp->tag[0]);
538 : : }
539 [ + - ]: 81 : if (lsp->n_addresses) {
540 : 81 : ds_put_cstr(s, " addresses: [");
541 [ + + ]: 168 : for (size_t j = 0; j < lsp->n_addresses; j++) {
542 [ + + ]: 87 : ds_put_format(s, "%s\"%s\"",
543 : : j == 0 ? "" : ", ",
544 : 87 : lsp->addresses[j]);
545 : : }
546 : 81 : ds_put_cstr(s, "]\n");
547 : : }
548 : : }
549 : 33 : }
550 : :
551 : : static void
552 : 42 : nbctl_init(struct ctl_context *ctx OVS_UNUSED)
553 : : {
554 : 42 : }
555 : :
556 : : static void
557 : 1 : nbctl_pre_sync(struct ctl_context *ctx OVS_UNUSED)
558 : : {
559 [ + - ]: 1 : if (wait_type != NBCTL_WAIT_NONE) {
560 : 1 : force_wait = true;
561 : : } else {
562 [ # # ]: 0 : VLOG_INFO("\"sync\" command has no effect without --wait");
563 : : }
564 : 1 : }
565 : :
566 : : static void
567 : 1 : nbctl_sync(struct ctl_context *ctx OVS_UNUSED)
568 : : {
569 : 1 : }
570 : :
571 : : static void
572 : 22 : nbctl_show(struct ctl_context *ctx)
573 : : {
574 : : const struct nbrec_logical_switch *ls;
575 : :
576 [ + + ]: 22 : if (ctx->argc == 2) {
577 : 7 : ls = ls_by_name_or_uuid(ctx, ctx->argv[1], false);
578 [ + + ]: 7 : if (ls) {
579 : 7 : print_ls(ls, &ctx->output);
580 : : }
581 : : } else {
582 [ + + ]: 46 : NBREC_LOGICAL_SWITCH_FOR_EACH(ls, ctx->idl) {
583 : 31 : print_ls(ls, &ctx->output);
584 : : }
585 : : }
586 : : const struct nbrec_logical_router *lr;
587 : :
588 [ + + ]: 22 : if (ctx->argc == 2) {
589 : 7 : lr = lr_by_name_or_uuid(ctx, ctx->argv[1], false);
590 [ + + ]: 7 : if (lr) {
591 : 7 : print_lr(lr, &ctx->output);
592 : : }
593 : : } else {
594 [ + + ]: 29 : NBREC_LOGICAL_ROUTER_FOR_EACH(lr, ctx->idl) {
595 : 14 : print_lr(lr, &ctx->output);
596 : : }
597 : : }
598 : 22 : }
599 : :
600 : : static void
601 : 92 : nbctl_ls_add(struct ctl_context *ctx)
602 : : {
603 [ + + ]: 92 : const char *ls_name = ctx->argc == 2 ? ctx->argv[1] : NULL;
604 : :
605 : 92 : bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
606 : 92 : bool add_duplicate = shash_find(&ctx->options, "--add-duplicate") != NULL;
607 [ + + ][ + + ]: 92 : if (may_exist && add_duplicate) {
608 : 1 : ctl_fatal("--may-exist and --add-duplicate may not be used together");
609 : : }
610 : :
611 [ + + ]: 91 : if (ls_name) {
612 [ + + ]: 87 : if (!add_duplicate) {
613 : : const struct nbrec_logical_switch *ls;
614 [ + + ]: 147 : NBREC_LOGICAL_SWITCH_FOR_EACH (ls, ctx->idl) {
615 [ + + ]: 62 : if (!strcmp(ls->name, ls_name)) {
616 [ + + ]: 2 : if (may_exist) {
617 : 1 : return;
618 : : }
619 : 1 : ctl_fatal("%s: a switch with this name already exists",
620 : : ls_name);
621 : : }
622 : : }
623 : : }
624 [ + + ]: 4 : } else if (may_exist) {
625 : 1 : ctl_fatal("--may-exist requires specifying a name");
626 [ + + ]: 3 : } else if (add_duplicate) {
627 : 1 : ctl_fatal("--add-duplicate requires specifying a name");
628 : : }
629 : :
630 : : struct nbrec_logical_switch *ls;
631 : 87 : ls = nbrec_logical_switch_insert(ctx->txn);
632 [ + + ]: 87 : if (ls_name) {
633 : 85 : nbrec_logical_switch_set_name(ls, ls_name);
634 : : }
635 : : }
636 : :
637 : : static void
638 : 6 : nbctl_ls_del(struct ctl_context *ctx)
639 : : {
640 : 6 : bool must_exist = !shash_find(&ctx->options, "--if-exists");
641 : 6 : const char *id = ctx->argv[1];
642 : : const struct nbrec_logical_switch *ls;
643 : :
644 : 6 : ls = ls_by_name_or_uuid(ctx, id, must_exist);
645 [ + + ]: 4 : if (!ls) {
646 : 1 : return;
647 : : }
648 : :
649 : 3 : nbrec_logical_switch_delete(ls);
650 : : }
651 : :
652 : : static void
653 : 3 : nbctl_ls_list(struct ctl_context *ctx)
654 : : {
655 : : const struct nbrec_logical_switch *ls;
656 : : struct smap lswitches;
657 : :
658 : 3 : smap_init(&lswitches);
659 [ + + ]: 7 : NBREC_LOGICAL_SWITCH_FOR_EACH(ls, ctx->idl) {
660 : 4 : smap_add_format(&lswitches, ls->name, UUID_FMT " (%s)",
661 : 12 : UUID_ARGS(&ls->header_.uuid), ls->name);
662 : : }
663 : 3 : const struct smap_node **nodes = smap_sort(&lswitches);
664 [ + + ]: 7 : for (size_t i = 0; i < smap_count(&lswitches); i++) {
665 : 4 : const struct smap_node *node = nodes[i];
666 : 4 : ds_put_format(&ctx->output, "%s\n", node->value);
667 : : }
668 : 3 : smap_destroy(&lswitches);
669 : 3 : free(nodes);
670 : 3 : }
671 : :
672 : : static const struct nbrec_logical_switch_port *
673 : 541 : lsp_by_name_or_uuid(struct ctl_context *ctx, const char *id,
674 : : bool must_exist)
675 : : {
676 : 541 : const struct nbrec_logical_switch_port *lsp = NULL;
677 : :
678 : : struct uuid lsp_uuid;
679 : 541 : bool is_uuid = uuid_from_string(&lsp_uuid, id);
680 [ - + ]: 541 : if (is_uuid) {
681 : 0 : lsp = nbrec_logical_switch_port_get_for_uuid(ctx->idl, &lsp_uuid);
682 : : }
683 : :
684 [ + - ]: 541 : if (!lsp) {
685 [ + + ]: 2763 : NBREC_LOGICAL_SWITCH_PORT_FOR_EACH(lsp, ctx->idl) {
686 [ + + ]: 2519 : if (!strcmp(lsp->name, id)) {
687 : 297 : break;
688 : : }
689 : : }
690 : : }
691 : :
692 [ + + ][ - + ]: 541 : if (!lsp && must_exist) {
693 [ # # ]: 0 : ctl_fatal("%s: port %s not found", id, is_uuid ? "UUID" : "name");
694 : : }
695 : :
696 : 541 : return lsp;
697 : : }
698 : :
699 : : /* Returns the logical switch that contains 'lsp'. */
700 : : static const struct nbrec_logical_switch *
701 : 6 : lsp_to_ls(const struct ovsdb_idl *idl,
702 : : const struct nbrec_logical_switch_port *lsp)
703 : : {
704 : : const struct nbrec_logical_switch *ls;
705 [ + - ]: 11 : NBREC_LOGICAL_SWITCH_FOR_EACH (ls, idl) {
706 [ + + ]: 16 : for (size_t i = 0; i < ls->n_ports; i++) {
707 [ + + ]: 11 : if (ls->ports[i] == lsp) {
708 : 6 : return ls;
709 : : }
710 : : }
711 : : }
712 : :
713 : : /* Can't happen because of the database schema */
714 : 0 : ctl_fatal("logical port %s is not part of any logical switch",
715 : : lsp->name);
716 : : }
717 : :
718 : : static const char *
719 : 1 : ls_get_name(const struct nbrec_logical_switch *ls,
720 : : char uuid_s[UUID_LEN + 1], size_t uuid_s_size)
721 : : {
722 [ + - ]: 1 : if (ls->name[0]) {
723 : 1 : return ls->name;
724 : : }
725 : 0 : snprintf(uuid_s, uuid_s_size, UUID_FMT, UUID_ARGS(&ls->header_.uuid));
726 : 0 : return uuid_s;
727 : : }
728 : :
729 : : static void
730 : 252 : nbctl_lsp_add(struct ctl_context *ctx)
731 : : {
732 : 252 : bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
733 : :
734 : : const struct nbrec_logical_switch *ls;
735 : 252 : ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
736 : :
737 : : const char *parent_name;
738 : : int64_t tag;
739 [ + + ]: 252 : if (ctx->argc == 3) {
740 : 236 : parent_name = NULL;
741 : 236 : tag = -1;
742 [ + - ]: 16 : } else if (ctx->argc == 5) {
743 : : /* Validate tag. */
744 : 16 : parent_name = ctx->argv[3];
745 [ + - ]: 16 : if (!ovs_scan(ctx->argv[4], "%"SCNd64, &tag)
746 [ + - ][ - + ]: 16 : || tag < 0 || tag > 4095) {
747 : 0 : ctl_fatal("%s: invalid tag", ctx->argv[4]);
748 : : }
749 : : } else {
750 : 0 : ctl_fatal("lsp-add with parent must also specify a tag");
751 : : }
752 : :
753 : 252 : const char *lsp_name = ctx->argv[2];
754 : : const struct nbrec_logical_switch_port *lsp;
755 : 252 : lsp = lsp_by_name_or_uuid(ctx, lsp_name, false);
756 [ + + ]: 252 : if (lsp) {
757 [ + + ]: 8 : if (!may_exist) {
758 : 2 : ctl_fatal("%s: a port with this name already exists",
759 : : lsp_name);
760 : : }
761 : :
762 : : const struct nbrec_logical_switch *lsw;
763 : 6 : lsw = lsp_to_ls(ctx->idl, lsp);
764 [ + + ]: 6 : if (lsw != ls) {
765 : : char uuid_s[UUID_LEN + 1];
766 : 1 : ctl_fatal("%s: port already exists but in switch %s", lsp_name,
767 : : ls_get_name(lsw, uuid_s, sizeof uuid_s));
768 : : }
769 : :
770 [ + + ]: 5 : if (parent_name) {
771 [ + + ]: 4 : if (!lsp->parent_name) {
772 : 1 : ctl_fatal("%s: port already exists but has no parent",
773 : : lsp_name);
774 [ + + ]: 3 : } else if (strcmp(parent_name, lsp->parent_name)) {
775 : 1 : ctl_fatal("%s: port already exists with different parent %s",
776 : : lsp_name, lsp->parent_name);
777 : : }
778 : :
779 [ + + ]: 2 : if (!lsp->n_tag_request) {
780 : 1 : ctl_fatal("%s: port already exists but has no tag_request",
781 : : lsp_name);
782 [ + - ]: 1 : } else if (lsp->tag_request[0] != tag) {
783 : 1 : ctl_fatal("%s: port already exists with different "
784 : : "tag_request %"PRId64, lsp_name,
785 : 1 : lsp->tag_request[0]);
786 : : }
787 : : } else {
788 [ - + ]: 1 : if (lsp->parent_name) {
789 : 0 : ctl_fatal("%s: port already exists but has parent %s",
790 : : lsp_name, lsp->parent_name);
791 : : }
792 : : }
793 : :
794 : 1 : return;
795 : : }
796 : :
797 : : /* Create the logical port. */
798 : 244 : lsp = nbrec_logical_switch_port_insert(ctx->txn);
799 : 244 : nbrec_logical_switch_port_set_name(lsp, lsp_name);
800 [ + + ]: 244 : if (tag >= 0) {
801 : 12 : nbrec_logical_switch_port_set_parent_name(lsp, parent_name);
802 : 12 : nbrec_logical_switch_port_set_tag_request(lsp, &tag, 1);
803 : : }
804 : :
805 : : /* Insert the logical port into the logical switch. */
806 : 244 : nbrec_logical_switch_verify_ports(ls);
807 : 244 : struct nbrec_logical_switch_port **new_ports = xmalloc(sizeof *new_ports *
808 : 244 : (ls->n_ports + 1));
809 : 244 : memcpy(new_ports, ls->ports, sizeof *new_ports * ls->n_ports);
810 : 244 : new_ports[ls->n_ports] = CONST_CAST(struct nbrec_logical_switch_port *,
811 : : lsp);
812 : 244 : nbrec_logical_switch_set_ports(ls, new_ports, ls->n_ports + 1);
813 : 244 : free(new_ports);
814 : : }
815 : :
816 : : /* Removes logical switch port 'ls->ports[idx]'. */
817 : : static void
818 : 7 : remove_lsp(const struct nbrec_logical_switch *ls, size_t idx)
819 : : {
820 : 7 : const struct nbrec_logical_switch_port *lsp = ls->ports[idx];
821 : :
822 : : /* First remove 'lsp' from the array of ports. This is what will
823 : : * actually cause the logical port to be deleted when the transaction is
824 : : * sent to the database server (due to garbage collection). */
825 : 7 : struct nbrec_logical_switch_port **new_ports
826 : 7 : = xmemdup(ls->ports, sizeof *new_ports * ls->n_ports);
827 : 7 : new_ports[idx] = new_ports[ls->n_ports - 1];
828 : 7 : nbrec_logical_switch_verify_ports(ls);
829 : 7 : nbrec_logical_switch_set_ports(ls, new_ports, ls->n_ports - 1);
830 : 7 : free(new_ports);
831 : :
832 : : /* Delete 'lsp' from the IDL. This won't have a real effect on the
833 : : * database server (the IDL will suppress it in fact) but it means that it
834 : : * won't show up when we iterate with NBREC_LOGICAL_SWITCH_PORT_FOR_EACH
835 : : * later. */
836 : 7 : nbrec_logical_switch_port_delete(lsp);
837 : 7 : }
838 : :
839 : : static void
840 : 7 : nbctl_lsp_del(struct ctl_context *ctx)
841 : : {
842 : 7 : bool must_exist = !shash_find(&ctx->options, "--if-exists");
843 : : const struct nbrec_logical_switch_port *lsp;
844 : :
845 : 7 : lsp = lsp_by_name_or_uuid(ctx, ctx->argv[1], must_exist);
846 [ - + ]: 7 : if (!lsp) {
847 : 0 : return;
848 : : }
849 : :
850 : : /* Find the switch that contains 'lsp', then delete it. */
851 : : const struct nbrec_logical_switch *ls;
852 [ + - ]: 8 : NBREC_LOGICAL_SWITCH_FOR_EACH (ls, ctx->idl) {
853 [ + + ]: 16 : for (size_t i = 0; i < ls->n_ports; i++) {
854 [ + + ]: 15 : if (ls->ports[i] == lsp) {
855 : 7 : remove_lsp(ls, i);
856 : 7 : return;
857 : : }
858 : : }
859 : : }
860 : :
861 : : /* Can't happen because of the database schema. */
862 : 0 : ctl_fatal("logical port %s is not part of any logical switch",
863 : 0 : ctx->argv[1]);
864 : : }
865 : :
866 : : static void
867 : 3 : nbctl_lsp_list(struct ctl_context *ctx)
868 : : {
869 : 3 : const char *id = ctx->argv[1];
870 : : const struct nbrec_logical_switch *ls;
871 : : struct smap lsps;
872 : : size_t i;
873 : :
874 : 3 : ls = ls_by_name_or_uuid(ctx, id, true);
875 : :
876 : 3 : smap_init(&lsps);
877 [ + + ]: 7 : for (i = 0; i < ls->n_ports; i++) {
878 : 4 : const struct nbrec_logical_switch_port *lsp = ls->ports[i];
879 : 4 : smap_add_format(&lsps, lsp->name, UUID_FMT " (%s)",
880 : 12 : UUID_ARGS(&lsp->header_.uuid), lsp->name);
881 : : }
882 : 3 : const struct smap_node **nodes = smap_sort(&lsps);
883 [ + + ]: 7 : for (i = 0; i < smap_count(&lsps); i++) {
884 : 4 : const struct smap_node *node = nodes[i];
885 : 4 : ds_put_format(&ctx->output, "%s\n", node->value);
886 : : }
887 : 3 : smap_destroy(&lsps);
888 : 3 : free(nodes);
889 : 3 : }
890 : :
891 : : static void
892 : 0 : nbctl_lsp_get_parent(struct ctl_context *ctx)
893 : : {
894 : : const struct nbrec_logical_switch_port *lsp;
895 : :
896 : 0 : lsp = lsp_by_name_or_uuid(ctx, ctx->argv[1], true);
897 [ # # ]: 0 : if (lsp->parent_name) {
898 : 0 : ds_put_format(&ctx->output, "%s\n", lsp->parent_name);
899 : : }
900 : 0 : }
901 : :
902 : : static void
903 : 18 : nbctl_lsp_get_tag(struct ctl_context *ctx)
904 : : {
905 : : const struct nbrec_logical_switch_port *lsp;
906 : :
907 : 18 : lsp = lsp_by_name_or_uuid(ctx, ctx->argv[1], true);
908 [ + + ]: 18 : if (lsp->n_tag > 0) {
909 : 17 : ds_put_format(&ctx->output, "%"PRId64"\n", lsp->tag[0]);
910 : : }
911 : 18 : }
912 : :
913 : : static void
914 : 169 : nbctl_lsp_set_addresses(struct ctl_context *ctx)
915 : : {
916 : 169 : const char *id = ctx->argv[1];
917 : : const struct nbrec_logical_switch_port *lsp;
918 : :
919 : 169 : lsp = lsp_by_name_or_uuid(ctx, id, true);
920 : :
921 : : int i;
922 [ + + ]: 352 : for (i = 2; i < ctx->argc; i++) {
923 : : struct eth_addr ea;
924 : :
925 [ + + ][ + + ]: 183 : if (strcmp(ctx->argv[i], "unknown") && strcmp(ctx->argv[i], "dynamic")
926 [ - + ]: 134 : && !ovs_scan(ctx->argv[i], ETH_ADDR_SCAN_FMT,
927 : : ETH_ADDR_SCAN_ARGS(ea))) {
928 : 0 : ctl_fatal("%s: Invalid address format. See ovn-nb(5). "
929 : : "Hint: An Ethernet address must be "
930 : : "listed before an IP address, together as a single "
931 : 0 : "argument.", ctx->argv[i]);
932 : : }
933 : : }
934 : :
935 : 169 : nbrec_logical_switch_port_set_addresses(lsp,
936 : 338 : (const char **) ctx->argv + 2, ctx->argc - 2);
937 : 169 : }
938 : :
939 : : static void
940 : 4 : nbctl_lsp_get_addresses(struct ctl_context *ctx)
941 : : {
942 : 4 : const char *id = ctx->argv[1];
943 : : const struct nbrec_logical_switch_port *lsp;
944 : : struct svec addresses;
945 : : const char *mac;
946 : : size_t i;
947 : :
948 : 4 : lsp = lsp_by_name_or_uuid(ctx, id, true);
949 : :
950 : 4 : svec_init(&addresses);
951 [ + + ]: 6 : for (i = 0; i < lsp->n_addresses; i++) {
952 : 2 : svec_add(&addresses, lsp->addresses[i]);
953 : : }
954 : 4 : svec_sort(&addresses);
955 [ + + ][ + + ]: 6 : SVEC_FOR_EACH(i, mac, &addresses) {
956 : 2 : ds_put_format(&ctx->output, "%s\n", mac);
957 : : }
958 : 4 : svec_destroy(&addresses);
959 : 4 : }
960 : :
961 : : static void
962 : 39 : nbctl_lsp_set_port_security(struct ctl_context *ctx)
963 : : {
964 : 39 : const char *id = ctx->argv[1];
965 : : const struct nbrec_logical_switch_port *lsp;
966 : :
967 : 39 : lsp = lsp_by_name_or_uuid(ctx, id, true);
968 : 39 : nbrec_logical_switch_port_set_port_security(lsp,
969 : 78 : (const char **) ctx->argv + 2, ctx->argc - 2);
970 : 39 : }
971 : :
972 : : static void
973 : 2 : nbctl_lsp_get_port_security(struct ctl_context *ctx)
974 : : {
975 : 2 : const char *id = ctx->argv[1];
976 : : const struct nbrec_logical_switch_port *lsp;
977 : : struct svec addrs;
978 : : const char *addr;
979 : : size_t i;
980 : :
981 : 2 : lsp = lsp_by_name_or_uuid(ctx, id, true);
982 : 2 : svec_init(&addrs);
983 [ + + ]: 4 : for (i = 0; i < lsp->n_port_security; i++) {
984 : 2 : svec_add(&addrs, lsp->port_security[i]);
985 : : }
986 : 2 : svec_sort(&addrs);
987 [ + + ][ + + ]: 4 : SVEC_FOR_EACH(i, addr, &addrs) {
988 : 2 : ds_put_format(&ctx->output, "%s\n", addr);
989 : : }
990 : 2 : svec_destroy(&addrs);
991 : 2 : }
992 : :
993 : : static void
994 : 12 : nbctl_lsp_get_up(struct ctl_context *ctx)
995 : : {
996 : 12 : const char *id = ctx->argv[1];
997 : : const struct nbrec_logical_switch_port *lsp;
998 : :
999 : 12 : lsp = lsp_by_name_or_uuid(ctx, id, true);
1000 [ + - ]: 24 : ds_put_format(&ctx->output,
1001 [ + + ]: 12 : "%s\n", (lsp->up && *lsp->up) ? "up" : "down");
1002 : 12 : }
1003 : :
1004 : : static bool
1005 : 3 : parse_enabled(const char *state)
1006 : : {
1007 [ + + ]: 3 : if (!strcasecmp(state, "enabled")) {
1008 : 1 : return true;
1009 [ + + ]: 2 : } else if (!strcasecmp(state, "disabled")) {
1010 : 1 : return false;
1011 : : } else {
1012 : 1 : ctl_fatal("%s: state must be \"enabled\" or \"disabled\"", state);
1013 : : }
1014 : : }
1015 : :
1016 : : static void
1017 : 0 : nbctl_lsp_set_enabled(struct ctl_context *ctx)
1018 : : {
1019 : 0 : const char *id = ctx->argv[1];
1020 : 0 : const char *state = ctx->argv[2];
1021 : : const struct nbrec_logical_switch_port *lsp;
1022 : :
1023 : 0 : lsp = lsp_by_name_or_uuid(ctx, id, true);
1024 : 0 : bool enabled = parse_enabled(state);
1025 : 0 : nbrec_logical_switch_port_set_enabled(lsp, &enabled, 1);
1026 : 0 : }
1027 : :
1028 : : static void
1029 : 0 : nbctl_lsp_get_enabled(struct ctl_context *ctx)
1030 : : {
1031 : 0 : const char *id = ctx->argv[1];
1032 : : const struct nbrec_logical_switch_port *lsp;
1033 : :
1034 : 0 : lsp = lsp_by_name_or_uuid(ctx, id, true);
1035 [ # # ]: 0 : ds_put_format(&ctx->output, "%s\n",
1036 [ # # ]: 0 : !lsp->enabled || *lsp->enabled ? "enabled" : "disabled");
1037 : 0 : }
1038 : :
1039 : : static void
1040 : 19 : nbctl_lsp_set_type(struct ctl_context *ctx)
1041 : : {
1042 : 19 : const char *id = ctx->argv[1];
1043 : 19 : const char *type = ctx->argv[2];
1044 : : const struct nbrec_logical_switch_port *lsp;
1045 : :
1046 : 19 : lsp = lsp_by_name_or_uuid(ctx, id, true);
1047 : 19 : nbrec_logical_switch_port_set_type(lsp, type);
1048 : 19 : }
1049 : :
1050 : : static void
1051 : 0 : nbctl_lsp_get_type(struct ctl_context *ctx)
1052 : : {
1053 : 0 : const char *id = ctx->argv[1];
1054 : : const struct nbrec_logical_switch_port *lsp;
1055 : :
1056 : 0 : lsp = lsp_by_name_or_uuid(ctx, id, true);
1057 : 0 : ds_put_format(&ctx->output, "%s\n", lsp->type);
1058 : 0 : }
1059 : :
1060 : : static void
1061 : 19 : nbctl_lsp_set_options(struct ctl_context *ctx)
1062 : : {
1063 : 19 : const char *id = ctx->argv[1];
1064 : : const struct nbrec_logical_switch_port *lsp;
1065 : : size_t i;
1066 : 19 : struct smap options = SMAP_INITIALIZER(&options);
1067 : :
1068 : 19 : lsp = lsp_by_name_or_uuid(ctx, id, true);
1069 [ + + ]: 52 : for (i = 2; i < ctx->argc; i++) {
1070 : : char *key, *value;
1071 : 33 : value = xstrdup(ctx->argv[i]);
1072 : 33 : key = strsep(&value, "=");
1073 [ + - ]: 33 : if (value) {
1074 : 33 : smap_add(&options, key, value);
1075 : : }
1076 : 33 : free(key);
1077 : : }
1078 : :
1079 : 19 : nbrec_logical_switch_port_set_options(lsp, &options);
1080 : :
1081 : 19 : smap_destroy(&options);
1082 : 19 : }
1083 : :
1084 : : static void
1085 : 0 : nbctl_lsp_get_options(struct ctl_context *ctx)
1086 : : {
1087 : 0 : const char *id = ctx->argv[1];
1088 : : const struct nbrec_logical_switch_port *lsp;
1089 : : struct smap_node *node;
1090 : :
1091 : 0 : lsp = lsp_by_name_or_uuid(ctx, id, true);
1092 [ # # ][ # # ]: 0 : SMAP_FOR_EACH(node, &lsp->options) {
1093 : 0 : ds_put_format(&ctx->output, "%s=%s\n", node->key, node->value);
1094 : : }
1095 : 0 : }
1096 : :
1097 : : static void
1098 : 0 : nbctl_lsp_set_dhcpv4_options(struct ctl_context *ctx)
1099 : : {
1100 : 0 : const char *id = ctx->argv[1];
1101 : : const struct nbrec_logical_switch_port *lsp;
1102 : :
1103 : 0 : lsp = lsp_by_name_or_uuid(ctx, id, true);
1104 : 0 : const struct nbrec_dhcp_options *dhcp_opt = NULL;
1105 [ # # ]: 0 : if (ctx->argc == 3 ) {
1106 : 0 : dhcp_opt = dhcp_options_get(ctx, ctx->argv[2], true);
1107 : : }
1108 : :
1109 [ # # ]: 0 : if (dhcp_opt) {
1110 : : ovs_be32 ip;
1111 : : unsigned int plen;
1112 : 0 : char *error = ip_parse_cidr(dhcp_opt->cidr, &ip, &plen);
1113 [ # # ]: 0 : if (error){
1114 : 0 : free(error);
1115 : 0 : ctl_fatal("DHCP options cidr '%s' is not IPv4", dhcp_opt->cidr);
1116 : : return;
1117 : : }
1118 : : }
1119 : 0 : nbrec_logical_switch_port_set_dhcpv4_options(lsp, dhcp_opt);
1120 : 0 : }
1121 : :
1122 : : static void
1123 : 0 : nbctl_lsp_get_dhcpv4_options(struct ctl_context *ctx)
1124 : : {
1125 : 0 : const char *id = ctx->argv[1];
1126 : : const struct nbrec_logical_switch_port *lsp;
1127 : :
1128 : 0 : lsp = lsp_by_name_or_uuid(ctx, id, true);
1129 [ # # ]: 0 : if (lsp->dhcpv4_options) {
1130 : 0 : ds_put_format(&ctx->output, UUID_FMT " (%s)\n",
1131 : 0 : UUID_ARGS(&lsp->dhcpv4_options->header_.uuid),
1132 : 0 : lsp->dhcpv4_options->cidr);
1133 : : }
1134 : 0 : }
1135 : :
1136 : : enum {
1137 : : DIR_FROM_LPORT,
1138 : : DIR_TO_LPORT
1139 : : };
1140 : :
1141 : : static int
1142 : 26 : dir_encode(const char *dir)
1143 : : {
1144 [ + + ]: 26 : if (!strcmp(dir, "from-lport")) {
1145 : 17 : return DIR_FROM_LPORT;
1146 [ + - ]: 9 : } else if (!strcmp(dir, "to-lport")) {
1147 : 9 : return DIR_TO_LPORT;
1148 : : }
1149 : :
1150 : 0 : OVS_NOT_REACHED();
1151 : : }
1152 : :
1153 : : static int
1154 : 13 : acl_cmp(const void *acl1_, const void *acl2_)
1155 : : {
1156 : 13 : const struct nbrec_acl *const *acl1p = acl1_;
1157 : 13 : const struct nbrec_acl *const *acl2p = acl2_;
1158 : 13 : const struct nbrec_acl *acl1 = *acl1p;
1159 : 13 : const struct nbrec_acl *acl2 = *acl2p;
1160 : :
1161 : 13 : int dir1 = dir_encode(acl1->direction);
1162 : 13 : int dir2 = dir_encode(acl2->direction);
1163 : :
1164 [ + + ]: 13 : if (dir1 != dir2) {
1165 [ - + ]: 5 : return dir1 < dir2 ? -1 : 1;
1166 [ + - ]: 8 : } else if (acl1->priority != acl2->priority) {
1167 [ + + ]: 8 : return acl1->priority > acl2->priority ? -1 : 1;
1168 : : } else {
1169 : 0 : return strcmp(acl1->match, acl2->match);
1170 : : }
1171 : : }
1172 : :
1173 : : static void
1174 : 4 : nbctl_acl_list(struct ctl_context *ctx)
1175 : : {
1176 : : const struct nbrec_logical_switch *ls;
1177 : : const struct nbrec_acl **acls;
1178 : : size_t i;
1179 : :
1180 : 4 : ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
1181 : :
1182 : 4 : acls = xmalloc(sizeof *acls * ls->n_acls);
1183 [ + + ]: 15 : for (i = 0; i < ls->n_acls; i++) {
1184 : 11 : acls[i] = ls->acls[i];
1185 : : }
1186 : :
1187 : 4 : qsort(acls, ls->n_acls, sizeof *acls, acl_cmp);
1188 : :
1189 [ + + ]: 15 : for (i = 0; i < ls->n_acls; i++) {
1190 : 11 : const struct nbrec_acl *acl = acls[i];
1191 [ + + ]: 11 : ds_put_format(&ctx->output, "%10s %5"PRId64" (%s) %s%s\n",
1192 : : acl->direction, acl->priority,
1193 : 11 : acl->match, acl->action, acl->log ? " log" : "");
1194 : : }
1195 : :
1196 : 4 : free(acls);
1197 : 4 : }
1198 : :
1199 : : static const char *
1200 : 22 : parse_direction(const char *arg)
1201 : : {
1202 : : /* Validate direction. Only require the first letter. */
1203 [ + + ]: 22 : if (arg[0] == 't') {
1204 : 10 : return "to-lport";
1205 [ + - ]: 12 : } else if (arg[0] == 'f') {
1206 : 12 : return "from-lport";
1207 : : } else {
1208 : 0 : ctl_fatal("%s: direction must be \"to-lport\" or \"from-lport\"", arg);
1209 : : }
1210 : : }
1211 : :
1212 : : static int
1213 : 21 : parse_priority(const char *arg)
1214 : : {
1215 : : /* Validate priority. */
1216 : : int64_t priority;
1217 [ + - ]: 21 : if (!ovs_scan(arg, "%"SCNd64, &priority)
1218 [ + - ][ - + ]: 21 : || priority < 0 || priority > 32767) {
1219 : 0 : ctl_fatal("%s: priority must in range 0...32767", arg);
1220 : : }
1221 : 21 : return priority;
1222 : : }
1223 : :
1224 : : static void
1225 : 20 : nbctl_acl_add(struct ctl_context *ctx)
1226 : : {
1227 : : const struct nbrec_logical_switch *ls;
1228 : 20 : const char *action = ctx->argv[5];
1229 : :
1230 : 20 : ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
1231 : :
1232 : 20 : const char *direction = parse_direction(ctx->argv[2]);
1233 : 20 : int64_t priority = parse_priority(ctx->argv[3]);
1234 : :
1235 : : /* Validate action. */
1236 [ + - ][ + + ]: 20 : if (strcmp(action, "allow") && strcmp(action, "allow-related")
1237 [ - + ][ # # ]: 17 : && strcmp(action, "drop") && strcmp(action, "reject")) {
1238 : 0 : ctl_fatal("%s: action must be one of \"allow\", \"allow-related\", "
1239 : : "\"drop\", and \"reject\"", action);
1240 : : return;
1241 : : }
1242 : :
1243 : : /* Create the acl. */
1244 : 20 : struct nbrec_acl *acl = nbrec_acl_insert(ctx->txn);
1245 : 20 : nbrec_acl_set_priority(acl, priority);
1246 : 20 : nbrec_acl_set_direction(acl, direction);
1247 : 20 : nbrec_acl_set_match(acl, ctx->argv[4]);
1248 : 20 : nbrec_acl_set_action(acl, action);
1249 [ + + ]: 20 : if (shash_find(&ctx->options, "--log") != NULL) {
1250 : 2 : nbrec_acl_set_log(acl, true);
1251 : : }
1252 : :
1253 : : /* Insert the acl into the logical switch. */
1254 : 20 : nbrec_logical_switch_verify_acls(ls);
1255 : 20 : struct nbrec_acl **new_acls = xmalloc(sizeof *new_acls * (ls->n_acls + 1));
1256 : 20 : memcpy(new_acls, ls->acls, sizeof *new_acls * ls->n_acls);
1257 : 20 : new_acls[ls->n_acls] = acl;
1258 : 20 : nbrec_logical_switch_set_acls(ls, new_acls, ls->n_acls + 1);
1259 : 20 : free(new_acls);
1260 : 20 : }
1261 : :
1262 : : static void
1263 : 3 : nbctl_acl_del(struct ctl_context *ctx)
1264 : : {
1265 : : const struct nbrec_logical_switch *ls;
1266 : 3 : ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
1267 : :
1268 [ + + ][ + + ]: 3 : if (ctx->argc != 2 && ctx->argc != 3 && ctx->argc != 5) {
[ - + ]
1269 : 0 : ctl_fatal("cannot specify priority without match");
1270 : : }
1271 : :
1272 [ + + ]: 3 : if (ctx->argc == 2) {
1273 : : /* If direction, priority, and match are not specified, delete
1274 : : * all ACLs. */
1275 : 1 : nbrec_logical_switch_verify_acls(ls);
1276 : 1 : nbrec_logical_switch_set_acls(ls, NULL, 0);
1277 : 1 : return;
1278 : : }
1279 : :
1280 : 2 : const char *direction = parse_direction(ctx->argv[2]);
1281 : :
1282 : : /* If priority and match are not specified, delete all ACLs with the
1283 : : * specified direction. */
1284 [ + + ]: 2 : if (ctx->argc == 3) {
1285 : 1 : struct nbrec_acl **new_acls = xmalloc(sizeof *new_acls * ls->n_acls);
1286 : :
1287 : 1 : int n_acls = 0;
1288 [ + + ]: 7 : for (size_t i = 0; i < ls->n_acls; i++) {
1289 [ + + ]: 6 : if (strcmp(direction, ls->acls[i]->direction)) {
1290 : 3 : new_acls[n_acls++] = ls->acls[i];
1291 : : }
1292 : : }
1293 : :
1294 : 1 : nbrec_logical_switch_verify_acls(ls);
1295 : 1 : nbrec_logical_switch_set_acls(ls, new_acls, n_acls);
1296 : 1 : free(new_acls);
1297 : 1 : return;
1298 : : }
1299 : :
1300 : 1 : int64_t priority = parse_priority(ctx->argv[3]);
1301 : :
1302 : : /* Remove the matching rule. */
1303 [ + - ]: 2 : for (size_t i = 0; i < ls->n_acls; i++) {
1304 : 2 : struct nbrec_acl *acl = ls->acls[i];
1305 : :
1306 [ + + ][ + - ]: 2 : if (priority == acl->priority && !strcmp(ctx->argv[4], acl->match) &&
[ + - ]
1307 : 1 : !strcmp(direction, acl->direction)) {
1308 : 1 : struct nbrec_acl **new_acls
1309 : 1 : = xmemdup(ls->acls, sizeof *new_acls * ls->n_acls);
1310 : 1 : new_acls[i] = ls->acls[ls->n_acls - 1];
1311 : 1 : nbrec_logical_switch_verify_acls(ls);
1312 : 1 : nbrec_logical_switch_set_acls(ls, new_acls,
1313 : 1 : ls->n_acls - 1);
1314 : 1 : free(new_acls);
1315 : 1 : return;
1316 : : }
1317 : : }
1318 : : }
1319 : :
1320 : : static void
1321 : 29 : nbctl_lr_add(struct ctl_context *ctx)
1322 : : {
1323 [ + + ]: 29 : const char *lr_name = ctx->argc == 2 ? ctx->argv[1] : NULL;
1324 : :
1325 : 29 : bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
1326 : 29 : bool add_duplicate = shash_find(&ctx->options, "--add-duplicate") != NULL;
1327 [ + + ][ + + ]: 29 : if (may_exist && add_duplicate) {
1328 : 1 : ctl_fatal("--may-exist and --add-duplicate may not be used together");
1329 : : }
1330 : :
1331 [ + + ]: 28 : if (lr_name) {
1332 [ + + ]: 24 : if (!add_duplicate) {
1333 : : const struct nbrec_logical_router *lr;
1334 [ + + ]: 33 : NBREC_LOGICAL_ROUTER_FOR_EACH (lr, ctx->idl) {
1335 [ + + ]: 11 : if (!strcmp(lr->name, lr_name)) {
1336 [ + + ]: 2 : if (may_exist) {
1337 : 1 : return;
1338 : : }
1339 : 1 : ctl_fatal("%s: a router with this name already exists",
1340 : : lr_name);
1341 : : }
1342 : : }
1343 : : }
1344 [ + + ]: 4 : } else if (may_exist) {
1345 : 1 : ctl_fatal("--may-exist requires specifying a name");
1346 [ + + ]: 3 : } else if (add_duplicate) {
1347 : 1 : ctl_fatal("--add-duplicate requires specifying a name");
1348 : : }
1349 : :
1350 : : struct nbrec_logical_router *lr;
1351 : 24 : lr = nbrec_logical_router_insert(ctx->txn);
1352 [ + + ]: 24 : if (lr_name) {
1353 : 22 : nbrec_logical_router_set_name(lr, lr_name);
1354 : : }
1355 : : }
1356 : :
1357 : : static void
1358 : 5 : nbctl_lr_del(struct ctl_context *ctx)
1359 : : {
1360 : 5 : bool must_exist = !shash_find(&ctx->options, "--if-exists");
1361 : 5 : const char *id = ctx->argv[1];
1362 : : const struct nbrec_logical_router *lr;
1363 : :
1364 : 5 : lr = lr_by_name_or_uuid(ctx, id, must_exist);
1365 [ + + ]: 3 : if (!lr) {
1366 : 1 : return;
1367 : : }
1368 : :
1369 : 2 : nbrec_logical_router_delete(lr);
1370 : : }
1371 : :
1372 : : static void
1373 : 3 : nbctl_lr_list(struct ctl_context *ctx)
1374 : : {
1375 : : const struct nbrec_logical_router *lr;
1376 : : struct smap lrs;
1377 : :
1378 : 3 : smap_init(&lrs);
1379 [ + + ]: 7 : NBREC_LOGICAL_ROUTER_FOR_EACH(lr, ctx->idl) {
1380 : 4 : smap_add_format(&lrs, lr->name, UUID_FMT " (%s)",
1381 : 12 : UUID_ARGS(&lr->header_.uuid), lr->name);
1382 : : }
1383 : 3 : const struct smap_node **nodes = smap_sort(&lrs);
1384 [ + + ]: 7 : for (size_t i = 0; i < smap_count(&lrs); i++) {
1385 : 4 : const struct smap_node *node = nodes[i];
1386 : 4 : ds_put_format(&ctx->output, "%s\n", node->value);
1387 : : }
1388 : 3 : smap_destroy(&lrs);
1389 : 3 : free(nodes);
1390 : 3 : }
1391 : :
1392 : : static const struct nbrec_dhcp_options *
1393 : 0 : dhcp_options_get(struct ctl_context *ctx, const char *id, bool must_exist)
1394 : : {
1395 : : struct uuid dhcp_opts_uuid;
1396 : 0 : const struct nbrec_dhcp_options *dhcp_opts = NULL;
1397 [ # # ]: 0 : if (uuid_from_string(&dhcp_opts_uuid, id)) {
1398 : 0 : dhcp_opts = nbrec_dhcp_options_get_for_uuid(ctx->idl, &dhcp_opts_uuid);
1399 : : }
1400 : :
1401 [ # # ][ # # ]: 0 : if (!dhcp_opts && must_exist) {
1402 : 0 : ctl_fatal("%s: dhcp options UUID not found", id);
1403 : : }
1404 : 0 : return dhcp_opts;
1405 : : }
1406 : :
1407 : : static void
1408 : 0 : nbctl_dhcp_options_create(struct ctl_context *ctx)
1409 : : {
1410 : : /* Validate the cidr */
1411 : : ovs_be32 ip;
1412 : : unsigned int plen;
1413 : 0 : char *error = ip_parse_cidr(ctx->argv[1], &ip, &plen);
1414 [ # # ]: 0 : if (error){
1415 : : /* check if its IPv6 cidr */
1416 : 0 : free(error);
1417 : : struct in6_addr ipv6;
1418 : 0 : error = ipv6_parse_cidr(ctx->argv[1], &ipv6, &plen);
1419 [ # # ]: 0 : if (error) {
1420 : 0 : free(error);
1421 : 0 : ctl_fatal("Invalid cidr format '%s'", ctx->argv[1]);
1422 : : return;
1423 : : }
1424 : : }
1425 : :
1426 : 0 : struct nbrec_dhcp_options *dhcp_opts = nbrec_dhcp_options_insert(ctx->txn);
1427 : 0 : nbrec_dhcp_options_set_cidr(dhcp_opts, ctx->argv[1]);
1428 : :
1429 : 0 : struct smap ext_ids = SMAP_INITIALIZER(&ext_ids);
1430 [ # # ]: 0 : for (size_t i = 2; i < ctx->argc; i++) {
1431 : : char *key, *value;
1432 : 0 : value = xstrdup(ctx->argv[i]);
1433 : 0 : key = strsep(&value, "=");
1434 [ # # ]: 0 : if (value) {
1435 : 0 : smap_add(&ext_ids, key, value);
1436 : : }
1437 : 0 : free(key);
1438 : : }
1439 : :
1440 : 0 : nbrec_dhcp_options_set_external_ids(dhcp_opts, &ext_ids);
1441 : 0 : smap_destroy(&ext_ids);
1442 : 0 : }
1443 : :
1444 : : static void
1445 : 0 : nbctl_dhcp_options_set_options(struct ctl_context *ctx)
1446 : : {
1447 : 0 : const struct nbrec_dhcp_options *dhcp_opts = dhcp_options_get(
1448 : 0 : ctx, ctx->argv[1], true);
1449 : :
1450 : 0 : struct smap dhcp_options = SMAP_INITIALIZER(&dhcp_options);
1451 [ # # ]: 0 : for (size_t i = 2; i < ctx->argc; i++) {
1452 : : char *key, *value;
1453 : 0 : value = xstrdup(ctx->argv[i]);
1454 : 0 : key = strsep(&value, "=");
1455 [ # # ]: 0 : if (value) {
1456 : 0 : smap_add(&dhcp_options, key, value);
1457 : : }
1458 : 0 : free(key);
1459 : : }
1460 : :
1461 : 0 : nbrec_dhcp_options_set_options(dhcp_opts, &dhcp_options);
1462 : 0 : smap_destroy(&dhcp_options);
1463 : 0 : }
1464 : :
1465 : : static void
1466 : 0 : nbctl_dhcp_options_get_options(struct ctl_context *ctx)
1467 : : {
1468 : 0 : const struct nbrec_dhcp_options *dhcp_opts = dhcp_options_get(
1469 : 0 : ctx, ctx->argv[1], true);
1470 : :
1471 : : struct smap_node *node;
1472 [ # # ][ # # ]: 0 : SMAP_FOR_EACH(node, &dhcp_opts->options) {
1473 : 0 : ds_put_format(&ctx->output, "%s=%s\n", node->key, node->value);
1474 : : }
1475 : 0 : }
1476 : :
1477 : : static void
1478 : 0 : nbctl_dhcp_options_del(struct ctl_context *ctx)
1479 : : {
1480 : 0 : bool must_exist = !shash_find(&ctx->options, "--if-exists");
1481 : 0 : const char *id = ctx->argv[1];
1482 : : const struct nbrec_dhcp_options *dhcp_opts;
1483 : :
1484 : 0 : dhcp_opts = dhcp_options_get(ctx, id, must_exist);
1485 [ # # ]: 0 : if (!dhcp_opts) {
1486 : 0 : return;
1487 : : }
1488 : :
1489 : 0 : nbrec_dhcp_options_delete(dhcp_opts);
1490 : : }
1491 : :
1492 : : static void
1493 : 0 : nbctl_dhcp_options_list(struct ctl_context *ctx)
1494 : : {
1495 : : const struct nbrec_dhcp_options *dhcp_opts;
1496 : : struct smap dhcp_options;
1497 : :
1498 : 0 : smap_init(&dhcp_options);
1499 [ # # ]: 0 : NBREC_DHCP_OPTIONS_FOR_EACH(dhcp_opts, ctx->idl) {
1500 : 0 : smap_add_format(&dhcp_options, dhcp_opts->cidr, UUID_FMT,
1501 : 0 : UUID_ARGS(&dhcp_opts->header_.uuid));
1502 : : }
1503 : 0 : const struct smap_node **nodes = smap_sort(&dhcp_options);
1504 [ # # ]: 0 : for (size_t i = 0; i < smap_count(&dhcp_options); i++) {
1505 : 0 : const struct smap_node *node = nodes[i];
1506 : 0 : ds_put_format(&ctx->output, "%s\n", node->value);
1507 : : }
1508 : 0 : smap_destroy(&dhcp_options);
1509 : 0 : free(nodes);
1510 : 0 : }
1511 : :
1512 : : /* The caller must free the returned string. */
1513 : : static char *
1514 : 117 : normalize_ipv4_prefix(ovs_be32 ipv4, unsigned int plen)
1515 : : {
1516 : 117 : ovs_be32 network = ipv4 & be32_prefix_mask(plen);
1517 [ + + ]: 117 : if (plen == 32) {
1518 : 39 : return xasprintf(IP_FMT, IP_ARGS(network));
1519 : : } else {
1520 : 78 : return xasprintf(IP_FMT"/%d", IP_ARGS(network), plen);
1521 : : }
1522 : : }
1523 : :
1524 : : /* The caller must free the returned string. */
1525 : : static char *
1526 : 37 : normalize_ipv6_prefix(struct in6_addr ipv6, unsigned int plen)
1527 : : {
1528 : : char network_s[INET6_ADDRSTRLEN];
1529 : :
1530 : 37 : struct in6_addr mask = ipv6_create_mask(plen);
1531 : 37 : struct in6_addr network = ipv6_addr_bitand(&ipv6, &mask);
1532 : :
1533 : 37 : inet_ntop(AF_INET6, &network, network_s, INET6_ADDRSTRLEN);
1534 [ + + ]: 37 : if (plen == 128) {
1535 : 14 : return xasprintf("%s", network_s);
1536 : : } else {
1537 : 37 : return xasprintf("%s/%d", network_s, plen);
1538 : : }
1539 : : }
1540 : :
1541 : : /* The caller must free the returned string. */
1542 : : static char *
1543 : 154 : normalize_prefix_str(const char *orig_prefix)
1544 : : {
1545 : : unsigned int plen;
1546 : : ovs_be32 ipv4;
1547 : : char *error;
1548 : :
1549 : 154 : error = ip_parse_cidr(orig_prefix, &ipv4, &plen);
1550 [ + + ]: 154 : if (!error) {
1551 : 117 : return normalize_ipv4_prefix(ipv4, plen);
1552 : : } else {
1553 : : struct in6_addr ipv6;
1554 : 37 : free(error);
1555 : :
1556 : 37 : error = ipv6_parse_cidr(orig_prefix, &ipv6, &plen);
1557 [ - + ]: 37 : if (error) {
1558 : 0 : free(error);
1559 : 0 : return NULL;
1560 : : }
1561 : 154 : return normalize_ipv6_prefix(ipv6, plen);
1562 : : }
1563 : : }
1564 : :
1565 : : static void
1566 : 34 : nbctl_lr_route_add(struct ctl_context *ctx)
1567 : : {
1568 : : const struct nbrec_logical_router *lr;
1569 : 34 : lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
1570 : : char *prefix, *next_hop;
1571 : :
1572 : 34 : prefix = normalize_prefix_str(ctx->argv[2]);
1573 [ - + ]: 34 : if (!prefix) {
1574 : 0 : ctl_fatal("bad prefix argument: %s", ctx->argv[2]);
1575 : : }
1576 : :
1577 : 34 : next_hop = normalize_prefix_str(ctx->argv[3]);
1578 [ - + ]: 34 : if (!next_hop) {
1579 : 0 : ctl_fatal("bad next hop argument: %s", ctx->argv[3]);
1580 : : }
1581 : :
1582 [ + + ]: 34 : if (strchr(prefix, '.')) {
1583 : : ovs_be32 hop_ipv4;
1584 [ - + ]: 28 : if (!ip_parse(ctx->argv[3], &hop_ipv4)) {
1585 : 28 : ctl_fatal("bad IPv4 nexthop argument: %s", ctx->argv[3]);
1586 : : }
1587 : : } else {
1588 : : struct in6_addr hop_ipv6;
1589 [ - + ]: 6 : if (!ipv6_parse(ctx->argv[3], &hop_ipv6)) {
1590 : 6 : ctl_fatal("bad IPv6 nexthop argument: %s", ctx->argv[3]);
1591 : : }
1592 : : }
1593 : :
1594 : 34 : bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
1595 [ + + ]: 66 : for (int i = 0; i < lr->n_static_routes; i++) {
1596 : 35 : const struct nbrec_logical_router_static_route *route
1597 : 35 : = lr->static_routes[i];
1598 : : char *rt_prefix;
1599 : :
1600 : 35 : rt_prefix = normalize_prefix_str(lr->static_routes[i]->ip_prefix);
1601 [ - + ]: 35 : if (!rt_prefix) {
1602 : : /* Ignore existing prefix we couldn't parse. */
1603 : 0 : continue;
1604 : : }
1605 : :
1606 [ + + ]: 35 : if (strcmp(rt_prefix, prefix)) {
1607 : 32 : free(rt_prefix);
1608 : 32 : continue;
1609 : : }
1610 : :
1611 [ + + ]: 3 : if (!may_exist) {
1612 : 1 : free(rt_prefix);
1613 : 1 : ctl_fatal("duplicate prefix: %s", prefix);
1614 : : }
1615 : :
1616 : : /* Update the next hop for an existing route. */
1617 : 2 : nbrec_logical_router_verify_static_routes(lr);
1618 : 2 : nbrec_logical_router_static_route_verify_ip_prefix(route);
1619 : 2 : nbrec_logical_router_static_route_verify_nexthop(route);
1620 : 2 : nbrec_logical_router_static_route_set_ip_prefix(route, prefix);
1621 : 2 : nbrec_logical_router_static_route_set_nexthop(route, next_hop);
1622 [ + + ]: 2 : if (ctx->argc == 5) {
1623 : 1 : nbrec_logical_router_static_route_set_output_port(route,
1624 : 1 : ctx->argv[4]);
1625 : : }
1626 : 2 : free(rt_prefix);
1627 : 2 : free(next_hop);
1628 : 2 : free(prefix);
1629 : 2 : return;
1630 : : }
1631 : :
1632 : : struct nbrec_logical_router_static_route *route;
1633 : 31 : route = nbrec_logical_router_static_route_insert(ctx->txn);
1634 : 31 : nbrec_logical_router_static_route_set_ip_prefix(route, prefix);
1635 : 31 : nbrec_logical_router_static_route_set_nexthop(route, next_hop);
1636 [ + + ]: 31 : if (ctx->argc == 5) {
1637 : 6 : nbrec_logical_router_static_route_set_output_port(route, ctx->argv[4]);
1638 : : }
1639 : :
1640 : 31 : nbrec_logical_router_verify_static_routes(lr);
1641 : 31 : struct nbrec_logical_router_static_route **new_routes
1642 : 31 : = xmalloc(sizeof *new_routes * (lr->n_static_routes + 1));
1643 : 31 : memcpy(new_routes, lr->static_routes,
1644 : 31 : sizeof *new_routes * lr->n_static_routes);
1645 : 31 : new_routes[lr->n_static_routes] = route;
1646 : 31 : nbrec_logical_router_set_static_routes(lr, new_routes,
1647 : 31 : lr->n_static_routes + 1);
1648 : 31 : free(new_routes);
1649 : 31 : free(next_hop);
1650 : 31 : free(prefix);
1651 : : }
1652 : :
1653 : : static void
1654 : 6 : nbctl_lr_route_del(struct ctl_context *ctx)
1655 : : {
1656 : : const struct nbrec_logical_router *lr;
1657 : 6 : lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
1658 : :
1659 [ + + ]: 6 : if (ctx->argc == 2) {
1660 : : /* If a prefix is not specified, delete all routes. */
1661 : 2 : nbrec_logical_router_set_static_routes(lr, NULL, 0);
1662 : 2 : return;
1663 : : }
1664 : :
1665 : 4 : char *prefix = normalize_prefix_str(ctx->argv[2]);
1666 [ - + ]: 4 : if (!prefix) {
1667 : 0 : ctl_fatal("bad prefix argument: %s", ctx->argv[2]);
1668 : : }
1669 : :
1670 [ + + ]: 11 : for (int i = 0; i < lr->n_static_routes; i++) {
1671 : 9 : char *rt_prefix = normalize_prefix_str(lr->static_routes[i]->ip_prefix);
1672 [ - + ]: 9 : if (!rt_prefix) {
1673 : : /* Ignore existing prefix we couldn't parse. */
1674 : 0 : continue;
1675 : : }
1676 : :
1677 [ + + ]: 9 : if (!strcmp(prefix, rt_prefix)) {
1678 : 2 : struct nbrec_logical_router_static_route **new_routes
1679 : 2 : = xmemdup(lr->static_routes,
1680 : 2 : sizeof *new_routes * lr->n_static_routes);
1681 : :
1682 : 2 : new_routes[i] = lr->static_routes[lr->n_static_routes - 1];
1683 : 2 : nbrec_logical_router_verify_static_routes(lr);
1684 : 2 : nbrec_logical_router_set_static_routes(lr, new_routes,
1685 : 2 : lr->n_static_routes - 1);
1686 : 2 : free(new_routes);
1687 : 2 : free(rt_prefix);
1688 : 2 : free(prefix);
1689 : 2 : return;
1690 : : }
1691 : 7 : free(rt_prefix);
1692 : : }
1693 : :
1694 [ + + ]: 2 : if (!shash_find(&ctx->options, "--if-exists")) {
1695 : 1 : ctl_fatal("no matching prefix: %s", prefix);
1696 : : }
1697 : 1 : free(prefix);
1698 : : }
1699 : :
1700 : : static const struct nbrec_logical_router_port *
1701 : 80 : lrp_by_name_or_uuid(struct ctl_context *ctx, const char *id, bool must_exist)
1702 : : {
1703 : 80 : const struct nbrec_logical_router_port *lrp = NULL;
1704 : :
1705 : : struct uuid lrp_uuid;
1706 : 80 : bool is_uuid = uuid_from_string(&lrp_uuid, id);
1707 [ - + ]: 80 : if (is_uuid) {
1708 : 0 : lrp = nbrec_logical_router_port_get_for_uuid(ctx->idl, &lrp_uuid);
1709 : : }
1710 : :
1711 [ + - ]: 80 : if (!lrp) {
1712 [ + + ]: 201 : NBREC_LOGICAL_ROUTER_PORT_FOR_EACH(lrp, ctx->idl) {
1713 [ + + ]: 138 : if (!strcmp(lrp->name, id)) {
1714 : 17 : break;
1715 : : }
1716 : : }
1717 : : }
1718 : :
1719 [ + + ][ - + ]: 80 : if (!lrp && must_exist) {
1720 [ # # ]: 0 : ctl_fatal("%s: port %s not found", id, is_uuid ? "UUID" : "name");
1721 : : }
1722 : :
1723 : 80 : return lrp;
1724 : : }
1725 : :
1726 : : /* Returns the logical router that contains 'lrp'. */
1727 : : static const struct nbrec_logical_router *
1728 : 8 : lrp_to_lr(const struct ovsdb_idl *idl,
1729 : : const struct nbrec_logical_router_port *lrp)
1730 : : {
1731 : : const struct nbrec_logical_router *lr;
1732 [ + - ]: 8 : NBREC_LOGICAL_ROUTER_FOR_EACH (lr, idl) {
1733 [ + - ]: 10 : for (size_t i = 0; i < lr->n_ports; i++) {
1734 [ + + ]: 10 : if (lr->ports[i] == lrp) {
1735 : 8 : return lr;
1736 : : }
1737 : : }
1738 : : }
1739 : :
1740 : : /* Can't happen because of the database schema */
1741 : 0 : ctl_fatal("port %s is not part of any logical router",
1742 : : lrp->name);
1743 : : }
1744 : :
1745 : : static const char *
1746 : 1 : lr_get_name(const struct nbrec_logical_router *lr, char uuid_s[UUID_LEN + 1],
1747 : : size_t uuid_s_size)
1748 : : {
1749 [ + - ]: 1 : if (lr->name[0]) {
1750 : 1 : return lr->name;
1751 : : }
1752 : 0 : snprintf(uuid_s, uuid_s_size, UUID_FMT, UUID_ARGS(&lr->header_.uuid));
1753 : 0 : return uuid_s;
1754 : : }
1755 : :
1756 : : static void
1757 : 73 : nbctl_lrp_add(struct ctl_context *ctx)
1758 : : {
1759 : 73 : bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
1760 : :
1761 : : const struct nbrec_logical_router *lr;
1762 : 73 : lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
1763 : :
1764 : 73 : const char *lrp_name = ctx->argv[2];
1765 : 73 : const char *mac = ctx->argv[3];
1766 : 73 : const char **networks = (const char **) &ctx->argv[4];
1767 : :
1768 : 73 : int n_networks = ctx->argc - 4;
1769 [ + + ]: 150 : for (int i = 4; i < ctx->argc; i++) {
1770 [ + + ]: 87 : if (strchr(ctx->argv[i], '=')) {
1771 : 10 : n_networks = i - 4;
1772 : 10 : break;
1773 : : }
1774 : : }
1775 : :
1776 [ - + ]: 73 : if (!n_networks) {
1777 : 0 : ctl_fatal("%s: router port requires specifying a network", lrp_name);
1778 : : }
1779 : :
1780 : 73 : char **settings = (char **) &ctx->argv[n_networks + 4];
1781 : 73 : int n_settings = ctx->argc - 4 - n_networks;
1782 : :
1783 : : const struct nbrec_logical_router_port *lrp;
1784 : 73 : lrp = lrp_by_name_or_uuid(ctx, lrp_name, false);
1785 [ + + ]: 73 : if (lrp) {
1786 [ + + ]: 10 : if (!may_exist) {
1787 : 2 : ctl_fatal("%s: a port with this name already exists",
1788 : : lrp_name);
1789 : : }
1790 : :
1791 : : const struct nbrec_logical_router *bound_lr;
1792 : 8 : bound_lr = lrp_to_lr(ctx->idl, lrp);
1793 [ + + ]: 8 : if (bound_lr != lr) {
1794 : : char uuid_s[UUID_LEN + 1];
1795 : 1 : ctl_fatal("%s: port already exists but in router %s", lrp_name,
1796 : : lr_get_name(bound_lr, uuid_s, sizeof uuid_s));
1797 : : }
1798 : :
1799 [ + + ]: 7 : if (strcmp(mac, lrp->mac)) {
1800 : 1 : ctl_fatal("%s: port already exists with mac %s", lrp_name,
1801 : : lrp->mac);
1802 : : }
1803 : :
1804 : 6 : struct sset new_networks = SSET_INITIALIZER(&new_networks);
1805 [ + + ]: 14 : for (int i = 0; i < n_networks; i++) {
1806 : 8 : sset_add(&new_networks, networks[i]);
1807 : : }
1808 : :
1809 : 6 : struct sset orig_networks = SSET_INITIALIZER(&orig_networks);
1810 : 6 : sset_add_array(&orig_networks, lrp->networks, lrp->n_networks);
1811 : :
1812 [ + + ]: 6 : if (!sset_equals(&orig_networks, &new_networks)) {
1813 : 2 : ctl_fatal("%s: port already exists with different network",
1814 : : lrp_name);
1815 : : }
1816 : :
1817 : 4 : sset_destroy(&orig_networks);
1818 : 4 : sset_destroy(&new_networks);
1819 : :
1820 : : /* Special-case sanity-check of peer ports. */
1821 : 4 : const char *peer = NULL;
1822 [ + + ]: 4 : for (int i = 0; i < n_settings; i++) {
1823 [ + - ]: 2 : if (!strncmp(settings[i], "peer=", 5)) {
1824 : 2 : peer = settings[i] + 5;
1825 : 2 : break;
1826 : : }
1827 : : }
1828 : :
1829 [ + + ][ + + ]: 4 : if ((!peer != !lrp->peer) ||
1830 [ - + ]: 2 : (lrp->peer && strcmp(peer, lrp->peer))) {
1831 : 1 : ctl_fatal("%s: port already exists with mismatching peer",
1832 : : lrp_name);
1833 : : }
1834 : :
1835 : 3 : return;
1836 : : }
1837 : :
1838 : : struct eth_addr ea;
1839 [ - + ]: 63 : if (!ovs_scan(mac, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(ea))) {
1840 : 0 : ctl_fatal("%s: invalid mac address %s", lrp_name, mac);
1841 : : }
1842 : :
1843 [ + + ]: 128 : for (int i = 0; i < n_networks; i++) {
1844 : : ovs_be32 ipv4;
1845 : : unsigned int plen;
1846 : 65 : char *error = ip_parse_cidr(networks[i], &ipv4, &plen);
1847 [ - + ]: 65 : if (error) {
1848 : 0 : free(error);
1849 : : struct in6_addr ipv6;
1850 : 0 : error = ipv6_parse_cidr(networks[i], &ipv6, &plen);
1851 [ # # ]: 0 : if (error) {
1852 : 0 : free(error);
1853 : 0 : ctl_fatal("%s: invalid network address: %s", lrp_name,
1854 : 0 : networks[i]);
1855 : : }
1856 : : }
1857 : : }
1858 : :
1859 : : /* Create the logical port. */
1860 : 63 : lrp = nbrec_logical_router_port_insert(ctx->txn);
1861 : 63 : nbrec_logical_router_port_set_name(lrp, lrp_name);
1862 : 63 : nbrec_logical_router_port_set_mac(lrp, mac);
1863 : 63 : nbrec_logical_router_port_set_networks(lrp, networks, n_networks);
1864 : :
1865 [ + + ]: 69 : for (int i = 0; i < n_settings; i++) {
1866 : 6 : ctl_set_column("Logical_Router_Port", &lrp->header_, settings[i],
1867 : : ctx->symtab);
1868 : : }
1869 : :
1870 : : /* Insert the logical port into the logical router. */
1871 : 63 : nbrec_logical_router_verify_ports(lr);
1872 : 63 : struct nbrec_logical_router_port **new_ports = xmalloc(sizeof *new_ports *
1873 : 63 : (lr->n_ports + 1));
1874 : 63 : memcpy(new_ports, lr->ports, sizeof *new_ports * lr->n_ports);
1875 : 63 : new_ports[lr->n_ports] = CONST_CAST(struct nbrec_logical_router_port *,
1876 : : lrp);
1877 : 63 : nbrec_logical_router_set_ports(lr, new_ports, lr->n_ports + 1);
1878 : 63 : free(new_ports);
1879 : : }
1880 : :
1881 : : /* Removes logical router port 'lr->ports[idx]'. */
1882 : : static void
1883 : 1 : remove_lrp(const struct nbrec_logical_router *lr, size_t idx)
1884 : : {
1885 : 1 : const struct nbrec_logical_router_port *lrp = lr->ports[idx];
1886 : :
1887 : : /* First remove 'lrp' from the array of ports. This is what will
1888 : : * actually cause the logical port to be deleted when the transaction is
1889 : : * sent to the database server (due to garbage collection). */
1890 : 1 : struct nbrec_logical_router_port **new_ports
1891 : 1 : = xmemdup(lr->ports, sizeof *new_ports * lr->n_ports);
1892 : 1 : new_ports[idx] = new_ports[lr->n_ports - 1];
1893 : 1 : nbrec_logical_router_verify_ports(lr);
1894 : 1 : nbrec_logical_router_set_ports(lr, new_ports, lr->n_ports - 1);
1895 : 1 : free(new_ports);
1896 : :
1897 : : /* Delete 'lrp' from the IDL. This won't have a real effect on
1898 : : * the database server (the IDL will suppress it in fact) but it
1899 : : * means that it won't show up when we iterate with
1900 : : * NBREC_LOGICAL_ROUTER_PORT_FOR_EACH later. */
1901 : 1 : nbrec_logical_router_port_delete(lrp);
1902 : 1 : }
1903 : :
1904 : : static void
1905 : 1 : nbctl_lrp_del(struct ctl_context *ctx)
1906 : : {
1907 : 1 : bool must_exist = !shash_find(&ctx->options, "--if-exists");
1908 : : const struct nbrec_logical_router_port *lrp;
1909 : :
1910 : 1 : lrp = lrp_by_name_or_uuid(ctx, ctx->argv[1], must_exist);
1911 [ - + ]: 1 : if (!lrp) {
1912 : 0 : return;
1913 : : }
1914 : :
1915 : : /* Find the router that contains 'lrp', then delete it. */
1916 : : const struct nbrec_logical_router *lr;
1917 [ + - ]: 1 : NBREC_LOGICAL_ROUTER_FOR_EACH (lr, ctx->idl) {
1918 [ + - ]: 1 : for (size_t i = 0; i < lr->n_ports; i++) {
1919 [ + - ]: 1 : if (lr->ports[i] == lrp) {
1920 : 1 : remove_lrp(lr, i);
1921 : 1 : return;
1922 : : }
1923 : : }
1924 : : }
1925 : :
1926 : : /* Can't happen because of the database schema. */
1927 : 0 : ctl_fatal("logical port %s is not part of any logical router",
1928 : 0 : ctx->argv[1]);
1929 : : }
1930 : :
1931 : : /* Print a list of logical router ports. */
1932 : : static void
1933 : 3 : nbctl_lrp_list(struct ctl_context *ctx)
1934 : : {
1935 : 3 : const char *id = ctx->argv[1];
1936 : : const struct nbrec_logical_router *lr;
1937 : : struct smap lrps;
1938 : : size_t i;
1939 : :
1940 : 3 : lr = lr_by_name_or_uuid(ctx, id, true);
1941 : :
1942 : 3 : smap_init(&lrps);
1943 [ + + ]: 7 : for (i = 0; i < lr->n_ports; i++) {
1944 : 4 : const struct nbrec_logical_router_port *lrp = lr->ports[i];
1945 : 4 : smap_add_format(&lrps, lrp->name, UUID_FMT " (%s)",
1946 : 12 : UUID_ARGS(&lrp->header_.uuid), lrp->name);
1947 : : }
1948 : 3 : const struct smap_node **nodes = smap_sort(&lrps);
1949 [ + + ]: 7 : for (i = 0; i < smap_count(&lrps); i++) {
1950 : 4 : const struct smap_node *node = nodes[i];
1951 : 4 : ds_put_format(&ctx->output, "%s\n", node->value);
1952 : : }
1953 : 3 : smap_destroy(&lrps);
1954 : 3 : free(nodes);
1955 : 3 : }
1956 : :
1957 : : /* Set the logical router port admin-enabled state. */
1958 : : static void
1959 : 3 : nbctl_lrp_set_enabled(struct ctl_context *ctx)
1960 : : {
1961 : 3 : const char *id = ctx->argv[1];
1962 : 3 : const char *state = ctx->argv[2];
1963 : : const struct nbrec_logical_router_port *lrp;
1964 : :
1965 : 3 : lrp = lrp_by_name_or_uuid(ctx, id, true);
1966 [ - + ]: 3 : if (!lrp) {
1967 : 0 : return;
1968 : : }
1969 : :
1970 : 3 : bool enabled = parse_enabled(state);
1971 : 2 : nbrec_logical_router_port_set_enabled(lrp, &enabled, 1);
1972 : : }
1973 : :
1974 : : /* Print admin-enabled state for logical router port. */
1975 : : static void
1976 : 3 : nbctl_lrp_get_enabled(struct ctl_context *ctx)
1977 : : {
1978 : 3 : const char *id = ctx->argv[1];
1979 : : const struct nbrec_logical_router_port *lrp;
1980 : :
1981 : 3 : lrp = lrp_by_name_or_uuid(ctx, id, true);
1982 [ - + ]: 3 : if (!lrp) {
1983 : 0 : return;
1984 : : }
1985 : :
1986 [ + + ]: 5 : ds_put_format(&ctx->output, "%s\n",
1987 [ + + ]: 2 : !lrp->enabled ||
1988 : 2 : *lrp->enabled ? "enabled" : "disabled");
1989 : : }
1990 : :
1991 : : struct ipv4_route {
1992 : : int plen;
1993 : : ovs_be32 addr;
1994 : : const struct nbrec_logical_router_static_route *route;
1995 : : };
1996 : :
1997 : : static int
1998 : 10 : ipv4_route_cmp(const void *route1_, const void *route2_)
1999 : : {
2000 : 10 : const struct ipv4_route *route1p = route1_;
2001 : 10 : const struct ipv4_route *route2p = route2_;
2002 : :
2003 [ + + ]: 10 : if (route1p->plen != route2p->plen) {
2004 [ + + ]: 7 : return route1p->plen > route2p->plen ? -1 : 1;
2005 [ + - ]: 3 : } else if (route1p->addr != route2p->addr) {
2006 [ - + ]: 3 : return ntohl(route1p->addr) < ntohl(route2p->addr) ? -1 : 1;
2007 : : } else {
2008 : 0 : return 0;
2009 : : }
2010 : : }
2011 : :
2012 : : struct ipv6_route {
2013 : : int plen;
2014 : : struct in6_addr addr;
2015 : : const struct nbrec_logical_router_static_route *route;
2016 : : };
2017 : :
2018 : : static int
2019 : 7 : ipv6_route_cmp(const void *route1_, const void *route2_)
2020 : : {
2021 : 7 : const struct ipv6_route *route1p = route1_;
2022 : 7 : const struct ipv6_route *route2p = route2_;
2023 : :
2024 [ + + ]: 7 : if (route1p->plen != route2p->plen) {
2025 [ + + ]: 5 : return route1p->plen > route2p->plen ? -1 : 1;
2026 : : }
2027 : 2 : return memcmp(&route1p->addr, &route2p->addr, sizeof(route1p->addr));
2028 : : }
2029 : :
2030 : : static void
2031 : 19 : print_route(const struct nbrec_logical_router_static_route *route, struct ds *s)
2032 : : {
2033 : :
2034 : 19 : char *prefix = normalize_prefix_str(route->ip_prefix);
2035 : 19 : char *next_hop = normalize_prefix_str(route->nexthop);
2036 : 19 : ds_put_format(s, "%25s %25s", prefix, next_hop);
2037 : 19 : free(prefix);
2038 : 19 : free(next_hop);
2039 : :
2040 [ + + ]: 19 : if (route->output_port) {
2041 : 7 : ds_put_format(s, " %s", route->output_port);
2042 : : }
2043 : 19 : ds_put_char(s, '\n');
2044 : 19 : }
2045 : :
2046 : : static void
2047 : 8 : nbctl_lr_route_list(struct ctl_context *ctx)
2048 : : {
2049 : : const struct nbrec_logical_router *lr;
2050 : : struct ipv4_route *ipv4_routes;
2051 : : struct ipv6_route *ipv6_routes;
2052 : 8 : size_t n_ipv4_routes = 0;
2053 : 8 : size_t n_ipv6_routes = 0;
2054 : :
2055 : 8 : lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
2056 : :
2057 : 8 : ipv4_routes = xmalloc(sizeof *ipv4_routes * lr->n_static_routes);
2058 : 8 : ipv6_routes = xmalloc(sizeof *ipv6_routes * lr->n_static_routes);
2059 : :
2060 [ + + ]: 27 : for (int i = 0; i < lr->n_static_routes; i++) {
2061 : 19 : const struct nbrec_logical_router_static_route *route
2062 : 19 : = lr->static_routes[i];
2063 : : unsigned int plen;
2064 : : ovs_be32 ipv4;
2065 : : char *error;
2066 : :
2067 : 19 : error = ip_parse_cidr(route->ip_prefix, &ipv4, &plen);
2068 [ + + ]: 19 : if (!error) {
2069 : 11 : ipv4_routes[n_ipv4_routes].plen = plen;
2070 : 11 : ipv4_routes[n_ipv4_routes].addr = ipv4;
2071 : 11 : ipv4_routes[n_ipv4_routes].route = route;
2072 : 11 : n_ipv4_routes++;
2073 : : } else {
2074 : 8 : free(error);
2075 : :
2076 : : struct in6_addr ipv6;
2077 : 8 : error = ipv6_parse_cidr(route->ip_prefix, &ipv6, &plen);
2078 [ + - ]: 8 : if (!error) {
2079 : 8 : ipv6_routes[n_ipv6_routes].plen = plen;
2080 : 8 : ipv6_routes[n_ipv6_routes].addr = ipv6;
2081 : 8 : ipv6_routes[n_ipv6_routes].route = route;
2082 : 8 : n_ipv6_routes++;
2083 : : } else {
2084 : : /* Invalid prefix. */
2085 [ # # ]: 0 : VLOG_WARN("router "UUID_FMT" (%s) has invalid prefix: %s",
2086 : : UUID_ARGS(&lr->header_.uuid), lr->name,
2087 : : route->ip_prefix);
2088 : 0 : free(error);
2089 : 19 : continue;
2090 : : }
2091 : : }
2092 : : }
2093 : :
2094 : 8 : qsort(ipv4_routes, n_ipv4_routes, sizeof *ipv4_routes, ipv4_route_cmp);
2095 : 8 : qsort(ipv6_routes, n_ipv6_routes, sizeof *ipv6_routes, ipv6_route_cmp);
2096 : :
2097 [ + + ]: 8 : if (n_ipv4_routes) {
2098 : 4 : ds_put_cstr(&ctx->output, "IPv4 Routes\n");
2099 : : }
2100 [ + + ]: 19 : for (int i = 0; i < n_ipv4_routes; i++) {
2101 : 11 : print_route(ipv4_routes[i].route, &ctx->output);
2102 : : }
2103 : :
2104 [ + + ]: 8 : if (n_ipv6_routes) {
2105 [ + + ]: 3 : ds_put_format(&ctx->output, "%sIPv6 Routes\n",
2106 : : n_ipv4_routes ? "\n" : "");
2107 : : }
2108 [ + + ]: 16 : for (int i = 0; i < n_ipv6_routes; i++) {
2109 : 8 : print_route(ipv6_routes[i].route, &ctx->output);
2110 : : }
2111 : :
2112 : 8 : free(ipv4_routes);
2113 : 8 : free(ipv6_routes);
2114 : 8 : }
2115 : :
2116 : : static const struct ctl_table_class tables[] = {
2117 : : {&nbrec_table_nb_global,
2118 : : {{&nbrec_table_nb_global, NULL, NULL},
2119 : : {NULL, NULL, NULL}}},
2120 : :
2121 : : {&nbrec_table_logical_switch,
2122 : : {{&nbrec_table_logical_switch, &nbrec_logical_switch_col_name, NULL},
2123 : : {NULL, NULL, NULL}}},
2124 : :
2125 : : {&nbrec_table_logical_switch_port,
2126 : : {{&nbrec_table_logical_switch_port, &nbrec_logical_switch_port_col_name,
2127 : : NULL},
2128 : : {NULL, NULL, NULL}}},
2129 : :
2130 : : {&nbrec_table_acl,
2131 : : {{NULL, NULL, NULL},
2132 : : {NULL, NULL, NULL}}},
2133 : :
2134 : : {&nbrec_table_load_balancer,
2135 : : {{NULL, NULL, NULL},
2136 : : {NULL, NULL, NULL}}},
2137 : :
2138 : : {&nbrec_table_logical_router,
2139 : : {{&nbrec_table_logical_router, &nbrec_logical_router_col_name, NULL},
2140 : : {NULL, NULL, NULL}}},
2141 : :
2142 : : {&nbrec_table_logical_router_port,
2143 : : {{&nbrec_table_logical_router_port, &nbrec_logical_router_port_col_name,
2144 : : NULL},
2145 : : {NULL, NULL, NULL}}},
2146 : :
2147 : : {&nbrec_table_logical_router_static_route,
2148 : : {{&nbrec_table_logical_router_static_route, NULL,
2149 : : NULL},
2150 : : {NULL, NULL, NULL}}},
2151 : :
2152 : : {&nbrec_table_nat,
2153 : : {{&nbrec_table_nat, NULL,
2154 : : NULL},
2155 : : {NULL, NULL, NULL}}},
2156 : :
2157 : : {&nbrec_table_address_set,
2158 : : {{&nbrec_table_address_set, &nbrec_address_set_col_name, NULL},
2159 : : {NULL, NULL, NULL}}},
2160 : :
2161 : : {&nbrec_table_dhcp_options,
2162 : : {{&nbrec_table_dhcp_options, NULL,
2163 : : NULL},
2164 : : {NULL, NULL, NULL}}},
2165 : :
2166 : : {NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}}
2167 : : };
2168 : :
2169 : : static void
2170 : 893 : run_prerequisites(struct ctl_command *commands, size_t n_commands,
2171 : : struct ovsdb_idl *idl)
2172 : : {
2173 : 893 : ovsdb_idl_add_table(idl, &nbrec_table_nb_global);
2174 [ + + ]: 893 : if (wait_type == NBCTL_WAIT_SB) {
2175 : 14 : ovsdb_idl_add_column(idl, &nbrec_nb_global_col_sb_cfg);
2176 [ - + ]: 879 : } else if (wait_type == NBCTL_WAIT_HV) {
2177 : 0 : ovsdb_idl_add_column(idl, &nbrec_nb_global_col_hv_cfg);
2178 : : }
2179 : :
2180 [ + + ]: 1966 : for (struct ctl_command *c = commands; c < &commands[n_commands]; c++) {
2181 [ + + ]: 1073 : if (c->syntax->prerequisites) {
2182 : : struct ctl_context ctx;
2183 : :
2184 : 169 : ds_init(&c->output);
2185 : 169 : c->table = NULL;
2186 : :
2187 : 169 : ctl_context_init(&ctx, c, idl, NULL, NULL, NULL);
2188 : 169 : (c->syntax->prerequisites)(&ctx);
2189 : 169 : ctl_context_done(&ctx, c);
2190 : :
2191 [ - + ]: 169 : ovs_assert(!c->output.string);
2192 [ - + ]: 169 : ovs_assert(!c->table);
2193 : : }
2194 : : }
2195 : 893 : }
2196 : :
2197 : : static bool
2198 : 893 : do_nbctl(const char *args, struct ctl_command *commands, size_t n_commands,
2199 : : struct ovsdb_idl *idl)
2200 : : {
2201 : : struct ovsdb_idl_txn *txn;
2202 : : enum ovsdb_idl_txn_status status;
2203 : : struct ovsdb_symbol_table *symtab;
2204 : : struct ctl_context ctx;
2205 : : struct ctl_command *c;
2206 : : struct shash_node *node;
2207 : 893 : int64_t next_cfg = 0;
2208 : 893 : char *error = NULL;
2209 : :
2210 : 893 : txn = the_idl_txn = ovsdb_idl_txn_create(idl);
2211 [ - + ]: 893 : if (dry_run) {
2212 : 0 : ovsdb_idl_txn_set_dry_run(txn);
2213 : : }
2214 : :
2215 : 893 : ovsdb_idl_txn_add_comment(txn, "ovs-nbctl: %s", args);
2216 : :
2217 : 893 : const struct nbrec_nb_global *nb = nbrec_nb_global_first(idl);
2218 [ + + ]: 893 : if (!nb) {
2219 : : /* XXX add verification that table is empty */
2220 : 49 : nb = nbrec_nb_global_insert(txn);
2221 : : }
2222 : :
2223 [ + + ]: 893 : if (wait_type != NBCTL_WAIT_NONE) {
2224 : 14 : ovsdb_idl_txn_increment(txn, &nb->header_, &nbrec_nb_global_col_nb_cfg,
2225 : : force_wait);
2226 : : }
2227 : :
2228 : 893 : symtab = ovsdb_symbol_table_create();
2229 [ + + ]: 1966 : for (c = commands; c < &commands[n_commands]; c++) {
2230 : 1073 : ds_init(&c->output);
2231 : 1073 : c->table = NULL;
2232 : : }
2233 : 893 : ctl_context_init(&ctx, NULL, idl, txn, symtab, NULL);
2234 [ + + ]: 1937 : for (c = commands; c < &commands[n_commands]; c++) {
2235 : 1073 : ctl_context_init_command(&ctx, c);
2236 [ + - ]: 1073 : if (c->syntax->run) {
2237 : 1073 : (c->syntax->run)(&ctx);
2238 : : }
2239 : 1044 : ctl_context_done_command(&ctx, c);
2240 : :
2241 [ - + ]: 1044 : if (ctx.try_again) {
2242 : 0 : ctl_context_done(&ctx, NULL);
2243 : 0 : goto try_again;
2244 : : }
2245 : : }
2246 : 864 : ctl_context_done(&ctx, NULL);
2247 : :
2248 [ + + ][ - + ]: 875 : SHASH_FOR_EACH (node, &symtab->sh) {
2249 : 11 : struct ovsdb_symbol *symbol = node->data;
2250 [ - + ]: 11 : if (!symbol->created) {
2251 : 0 : ctl_fatal("row id \"%s\" is referenced but never created (e.g. "
2252 : : "with \"-- --id=%s create ...\")",
2253 : : node->name, node->name);
2254 : : }
2255 [ - + ]: 11 : if (!symbol->strong_ref) {
2256 [ # # ]: 0 : if (!symbol->weak_ref) {
2257 [ # # ]: 0 : VLOG_WARN("row id \"%s\" was created but no reference to it "
2258 : : "was inserted, so it will not actually appear in "
2259 : : "the database", node->name);
2260 : : } else {
2261 [ # # ]: 0 : VLOG_WARN("row id \"%s\" was created but only a weak "
2262 : : "reference to it was inserted, so it will not "
2263 : : "actually appear in the database", node->name);
2264 : : }
2265 : : }
2266 : : }
2267 : :
2268 : 864 : status = ovsdb_idl_txn_commit_block(txn);
2269 [ + + ][ + - ]: 864 : if (wait_type != NBCTL_WAIT_NONE && status == TXN_SUCCESS) {
2270 : 14 : next_cfg = ovsdb_idl_txn_get_increment_new_value(txn);
2271 : : }
2272 [ + + ][ + - ]: 864 : if (status == TXN_UNCHANGED || status == TXN_SUCCESS) {
2273 [ + + ]: 1908 : for (c = commands; c < &commands[n_commands]; c++) {
2274 [ + + ]: 1044 : if (c->syntax->postprocess) {
2275 : 32 : ctl_context_init(&ctx, c, idl, txn, symtab, NULL);
2276 : 32 : (c->syntax->postprocess)(&ctx);
2277 : 32 : ctl_context_done(&ctx, c);
2278 : : }
2279 : : }
2280 : : }
2281 : 864 : error = xstrdup(ovsdb_idl_txn_get_error(txn));
2282 : :
2283 [ - - + - : 864 : switch (status) {
- - - ]
2284 : : case TXN_UNCOMMITTED:
2285 : : case TXN_INCOMPLETE:
2286 : 0 : OVS_NOT_REACHED();
2287 : :
2288 : : case TXN_ABORTED:
2289 : : /* Should not happen--we never call ovsdb_idl_txn_abort(). */
2290 : 0 : ctl_fatal("transaction aborted");
2291 : :
2292 : : case TXN_UNCHANGED:
2293 : : case TXN_SUCCESS:
2294 : 864 : break;
2295 : :
2296 : : case TXN_TRY_AGAIN:
2297 : 0 : goto try_again;
2298 : :
2299 : : case TXN_ERROR:
2300 : 0 : ctl_fatal("transaction error: %s", error);
2301 : :
2302 : : case TXN_NOT_LOCKED:
2303 : : /* Should not happen--we never call ovsdb_idl_set_lock(). */
2304 : 0 : ctl_fatal("database not locked");
2305 : :
2306 : : default:
2307 : 0 : OVS_NOT_REACHED();
2308 : : }
2309 : 864 : free(error);
2310 : :
2311 : 864 : ovsdb_symbol_table_destroy(symtab);
2312 : :
2313 [ + + ]: 1908 : for (c = commands; c < &commands[n_commands]; c++) {
2314 : 1044 : struct ds *ds = &c->output;
2315 : :
2316 [ + + ]: 1044 : if (c->table) {
2317 : 18 : table_print(c->table, &table_style);
2318 [ - + ]: 1026 : } else if (oneline) {
2319 : : size_t j;
2320 : :
2321 : 0 : ds_chomp(ds, '\n');
2322 [ # # ]: 0 : for (j = 0; j < ds->length; j++) {
2323 : 0 : int ch = ds->string[j];
2324 [ # # # ]: 0 : switch (ch) {
2325 : : case '\n':
2326 : 0 : fputs("\\n", stdout);
2327 : 0 : break;
2328 : :
2329 : : case '\\':
2330 : 0 : fputs("\\\\", stdout);
2331 : 0 : break;
2332 : :
2333 : : default:
2334 : 0 : putchar(ch);
2335 : : }
2336 : : }
2337 : 0 : putchar('\n');
2338 : : } else {
2339 : 1026 : fputs(ds_cstr(ds), stdout);
2340 : : }
2341 : 1044 : ds_destroy(&c->output);
2342 : 1044 : table_destroy(c->table);
2343 : 1044 : free(c->table);
2344 : :
2345 : 1044 : shash_destroy_free_data(&c->options);
2346 : : }
2347 : 864 : free(commands);
2348 : :
2349 [ + + ][ + - ]: 864 : if (wait_type != NBCTL_WAIT_NONE && status != TXN_UNCHANGED) {
2350 : 14 : ovsdb_idl_enable_reconnect(idl);
2351 : : for (;;) {
2352 : 19 : ovsdb_idl_run(idl);
2353 [ + + ]: 24 : NBREC_NB_GLOBAL_FOR_EACH (nb, idl) {
2354 : 38 : int64_t cur_cfg = (wait_type == NBCTL_WAIT_SB
2355 : : ? nb->sb_cfg
2356 [ + - ]: 19 : : nb->hv_cfg);
2357 [ + + ]: 19 : if (cur_cfg >= next_cfg) {
2358 : 14 : goto done;
2359 : : }
2360 : : }
2361 : 5 : ovsdb_idl_wait(idl);
2362 : 5 : poll_block();
2363 : 5 : }
2364 : : done: ;
2365 : : }
2366 : :
2367 : 864 : ovsdb_idl_txn_destroy(txn);
2368 : 864 : ovsdb_idl_destroy(idl);
2369 : :
2370 : 864 : return true;
2371 : :
2372 : : try_again:
2373 : : /* Our transaction needs to be rerun, or a prerequisite was not met. Free
2374 : : * resources and return so that the caller can try again. */
2375 [ # # ]: 0 : if (txn) {
2376 : 0 : ovsdb_idl_txn_abort(txn);
2377 : 0 : ovsdb_idl_txn_destroy(txn);
2378 : 0 : the_idl_txn = NULL;
2379 : : }
2380 : 0 : ovsdb_symbol_table_destroy(symtab);
2381 [ # # ]: 0 : for (c = commands; c < &commands[n_commands]; c++) {
2382 : 0 : ds_destroy(&c->output);
2383 : 0 : table_destroy(c->table);
2384 : 0 : free(c->table);
2385 : : }
2386 : 0 : free(error);
2387 : 864 : return false;
2388 : : }
2389 : :
2390 : : /* Frees the current transaction and the underlying IDL and then calls
2391 : : * exit(status).
2392 : : *
2393 : : * Freeing the transaction and the IDL is not strictly necessary, but it makes
2394 : : * for a clean memory leak report from valgrind in the normal case. That makes
2395 : : * it easier to notice real memory leaks. */
2396 : : static void
2397 : 29 : nbctl_exit(int status)
2398 : : {
2399 [ + - ]: 29 : if (the_idl_txn) {
2400 : 29 : ovsdb_idl_txn_abort(the_idl_txn);
2401 : 29 : ovsdb_idl_txn_destroy(the_idl_txn);
2402 : : }
2403 : 29 : ovsdb_idl_destroy(the_idl);
2404 : 29 : exit(status);
2405 : : }
2406 : :
2407 : : static const struct ctl_command_syntax nbctl_commands[] = {
2408 : : { "init", 0, 0, "", NULL, nbctl_init, NULL, "", RW },
2409 : : { "sync", 0, 0, "", nbctl_pre_sync, nbctl_sync, NULL, "", RO },
2410 : : { "show", 0, 1, "[SWITCH]", NULL, nbctl_show, NULL, "", RO },
2411 : :
2412 : : /* logical switch commands. */
2413 : : { "ls-add", 0, 1, "[SWITCH]", NULL, nbctl_ls_add, NULL,
2414 : : "--may-exist,--add-duplicate", RW },
2415 : : { "ls-del", 1, 1, "SWITCH", NULL, nbctl_ls_del, NULL, "--if-exists", RW },
2416 : : { "ls-list", 0, 0, "", NULL, nbctl_ls_list, NULL, "", RO },
2417 : :
2418 : : /* acl commands. */
2419 : : { "acl-add", 5, 5, "SWITCH DIRECTION PRIORITY MATCH ACTION", NULL,
2420 : : nbctl_acl_add, NULL, "--log", RW },
2421 : : { "acl-del", 1, 4, "SWITCH [DIRECTION [PRIORITY MATCH]]", NULL,
2422 : : nbctl_acl_del, NULL, "", RW },
2423 : : { "acl-list", 1, 1, "SWITCH", NULL, nbctl_acl_list, NULL, "", RO },
2424 : :
2425 : : /* logical switch port commands. */
2426 : : { "lsp-add", 2, 4, "SWITCH PORT [PARENT] [TAG]", NULL, nbctl_lsp_add,
2427 : : NULL, "--may-exist", RW },
2428 : : { "lsp-del", 1, 1, "PORT", NULL, nbctl_lsp_del, NULL, "--if-exists", RW },
2429 : : { "lsp-list", 1, 1, "SWITCH", NULL, nbctl_lsp_list, NULL, "", RO },
2430 : : { "lsp-get-parent", 1, 1, "PORT", NULL, nbctl_lsp_get_parent, NULL,
2431 : : "", RO },
2432 : : { "lsp-get-tag", 1, 1, "PORT", NULL, nbctl_lsp_get_tag, NULL, "", RO },
2433 : : { "lsp-set-addresses", 1, INT_MAX, "PORT [ADDRESS]...", NULL,
2434 : : nbctl_lsp_set_addresses, NULL, "", RW },
2435 : : { "lsp-get-addresses", 1, 1, "PORT", NULL, nbctl_lsp_get_addresses, NULL,
2436 : : "", RO },
2437 : : { "lsp-set-port-security", 0, INT_MAX, "PORT [ADDRS]...", NULL,
2438 : : nbctl_lsp_set_port_security, NULL, "", RW },
2439 : : { "lsp-get-port-security", 1, 1, "PORT", NULL,
2440 : : nbctl_lsp_get_port_security, NULL, "", RO },
2441 : : { "lsp-get-up", 1, 1, "PORT", NULL, nbctl_lsp_get_up, NULL, "", RO },
2442 : : { "lsp-set-enabled", 2, 2, "PORT STATE", NULL, nbctl_lsp_set_enabled,
2443 : : NULL, "", RW },
2444 : : { "lsp-get-enabled", 1, 1, "PORT", NULL, nbctl_lsp_get_enabled, NULL,
2445 : : "", RO },
2446 : : { "lsp-set-type", 2, 2, "PORT TYPE", NULL, nbctl_lsp_set_type, NULL,
2447 : : "", RW },
2448 : : { "lsp-get-type", 1, 1, "PORT", NULL, nbctl_lsp_get_type, NULL, "", RO },
2449 : : { "lsp-set-options", 1, INT_MAX, "PORT KEY=VALUE [KEY=VALUE]...", NULL,
2450 : : nbctl_lsp_set_options, NULL, "", RW },
2451 : : { "lsp-get-options", 1, 1, "PORT", NULL, nbctl_lsp_get_options, NULL,
2452 : : "", RO },
2453 : : { "lsp-set-dhcpv4-options", 1, 2, "PORT [DHCP_OPT_UUID]", NULL,
2454 : : nbctl_lsp_set_dhcpv4_options, NULL, "", RW },
2455 : : { "lsp-get-dhcpv4-options", 1, 1, "PORT", NULL,
2456 : : nbctl_lsp_get_dhcpv4_options, NULL, "", RO },
2457 : :
2458 : : /* logical router commands. */
2459 : : { "lr-add", 0, 1, "[ROUTER]", NULL, nbctl_lr_add, NULL,
2460 : : "--may-exist,--add-duplicate", RW },
2461 : : { "lr-del", 1, 1, "ROUTER", NULL, nbctl_lr_del, NULL, "--if-exists", RW },
2462 : : { "lr-list", 0, 0, "", NULL, nbctl_lr_list, NULL, "", RO },
2463 : :
2464 : : /* logical router port commands. */
2465 : : { "lrp-add", 4, INT_MAX,
2466 : : "ROUTER PORT MAC NETWORK... [COLUMN[:KEY]=VALUE]...",
2467 : : NULL, nbctl_lrp_add, NULL, "--may-exist", RW },
2468 : : { "lrp-del", 1, 1, "PORT", NULL, nbctl_lrp_del, NULL, "--if-exists", RW },
2469 : : { "lrp-list", 1, 1, "ROUTER", NULL, nbctl_lrp_list, NULL, "", RO },
2470 : : { "lrp-set-enabled", 2, 2, "PORT STATE", NULL, nbctl_lrp_set_enabled,
2471 : : NULL, "", RW },
2472 : : { "lrp-get-enabled", 1, 1, "PORT", NULL, nbctl_lrp_get_enabled,
2473 : : NULL, "", RO },
2474 : :
2475 : : /* logical router route commands. */
2476 : : { "lr-route-add", 3, 4, "ROUTER PREFIX NEXTHOP [PORT]", NULL,
2477 : : nbctl_lr_route_add, NULL, "--may-exist", RW },
2478 : : { "lr-route-del", 1, 2, "ROUTER [PREFIX]", NULL, nbctl_lr_route_del,
2479 : : NULL, "--if-exists", RW },
2480 : : { "lr-route-list", 1, 1, "ROUTER", NULL, nbctl_lr_route_list, NULL,
2481 : : "", RO },
2482 : :
2483 : : /* DHCP_Options commands */
2484 : : {"dhcp-options-create", 1, INT_MAX, "CIDR [EXTERNAL:IDS]", NULL,
2485 : : nbctl_dhcp_options_create, NULL, "", RW },
2486 : : {"dhcp-options-del", 1, 1, "DHCP_OPT_UUID", NULL,
2487 : : nbctl_dhcp_options_del, NULL, "", RW},
2488 : : {"dhcp-options-list", 0, 0, "", NULL, nbctl_dhcp_options_list, NULL, "", RO},
2489 : : {"dhcp-options-set-options", 1, INT_MAX, "DHCP_OPT_UUID KEY=VALUE [KEY=VALUE]...",
2490 : : NULL, nbctl_dhcp_options_set_options, NULL, "", RW },
2491 : : {"dhcp-options-get-options", 1, 1, "DHCP_OPT_UUID", NULL,
2492 : : nbctl_dhcp_options_get_options, NULL, "", RO },
2493 : :
2494 : : {NULL, 0, 0, NULL, NULL, NULL, NULL, "", RO},
2495 : : };
2496 : :
2497 : : /* Registers nbctl and common db commands. */
2498 : : static void
2499 : 893 : nbctl_cmd_init(void)
2500 : : {
2501 : 893 : ctl_init(tables, NULL, nbctl_exit);
2502 : 893 : ctl_register_commands(nbctl_commands);
2503 : 893 : }
|