LCOV - code coverage report
Current view: top level - ovn/utilities - ovn-nbctl.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 848 1088 77.9 %
Date: 2016-09-14 01:02:56 Functions: 62 76 81.6 %
Branches: 429 626 68.5 %

           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 : }

Generated by: LCOV version 1.12