LCOV - code coverage report
Current view: top level - lib - ofp-parse.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 607 909 66.8 %
Date: 2016-09-14 01:02:56 Functions: 28 31 90.3 %
Branches: 398 674 59.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <config.h>
      18                 :            : 
      19                 :            : #include <ctype.h>
      20                 :            : #include <errno.h>
      21                 :            : #include <stdlib.h>
      22                 :            : #include <netinet/in.h>
      23                 :            : 
      24                 :            : #include "byte-order.h"
      25                 :            : #include "learn.h"
      26                 :            : #include "multipath.h"
      27                 :            : #include "netdev.h"
      28                 :            : #include "nx-match.h"
      29                 :            : #include "openflow/openflow.h"
      30                 :            : #include "openvswitch/dynamic-string.h"
      31                 :            : #include "openvswitch/meta-flow.h"
      32                 :            : #include "openvswitch/ofp-actions.h"
      33                 :            : #include "openvswitch/ofp-parse.h"
      34                 :            : #include "openvswitch/ofp-util.h"
      35                 :            : #include "openvswitch/ofpbuf.h"
      36                 :            : #include "openvswitch/vconn.h"
      37                 :            : #include "ovs-thread.h"
      38                 :            : #include "packets.h"
      39                 :            : #include "simap.h"
      40                 :            : #include "socket-util.h"
      41                 :            : #include "util.h"
      42                 :            : 
      43                 :            : /* Parses 'str' as an 8-bit unsigned integer into '*valuep'.
      44                 :            :  *
      45                 :            :  * 'name' describes the value parsed in an error message, if any.
      46                 :            :  *
      47                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
      48                 :            :  * error.  The caller is responsible for freeing the returned string. */
      49                 :            : char * OVS_WARN_UNUSED_RESULT
      50                 :       1409 : str_to_u8(const char *str, const char *name, uint8_t *valuep)
      51                 :            : {
      52                 :            :     int value;
      53                 :            : 
      54 [ +  - ][ +  - ]:       1409 :     if (!str_to_int(str, 0, &value) || value < 0 || value > 255) {
                 [ -  + ]
      55                 :          0 :         return xasprintf("invalid %s \"%s\"", name, str);
      56                 :            :     }
      57                 :       1409 :     *valuep = value;
      58                 :       1409 :     return NULL;
      59                 :            : }
      60                 :            : 
      61                 :            : /* Parses 'str' as a 16-bit unsigned integer into '*valuep'.
      62                 :            :  *
      63                 :            :  * 'name' describes the value parsed in an error message, if any.
      64                 :            :  *
      65                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
      66                 :            :  * error.  The caller is responsible for freeing the returned string. */
      67                 :            : char * OVS_WARN_UNUSED_RESULT
      68                 :       1374 : str_to_u16(const char *str, const char *name, uint16_t *valuep)
      69                 :            : {
      70                 :            :     int value;
      71                 :            : 
      72 [ +  + ][ +  - ]:       1374 :     if (!str_to_int(str, 0, &value) || value < 0 || value > 65535) {
                 [ -  + ]
      73                 :         36 :         return xasprintf("invalid %s \"%s\"", name, str);
      74                 :            :     }
      75                 :       1338 :     *valuep = value;
      76                 :       1374 :     return NULL;
      77                 :            : }
      78                 :            : 
      79                 :            : /* Parses 'str' as a 32-bit unsigned integer into '*valuep'.
      80                 :            :  *
      81                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
      82                 :            :  * error.  The caller is responsible for freeing the returned string. */
      83                 :            : char * OVS_WARN_UNUSED_RESULT
      84                 :        760 : str_to_u32(const char *str, uint32_t *valuep)
      85                 :            : {
      86                 :            :     char *tail;
      87                 :            :     uint32_t value;
      88                 :            : 
      89         [ -  + ]:        760 :     if (!str[0]) {
      90                 :          0 :         return xstrdup("missing required numeric argument");
      91                 :            :     }
      92                 :            : 
      93                 :        760 :     errno = 0;
      94                 :        760 :     value = strtoul(str, &tail, 0);
      95 [ +  - ][ +  - ]:        760 :     if (errno == EINVAL || errno == ERANGE || *tail) {
                 [ -  + ]
      96                 :          0 :         return xasprintf("invalid numeric format %s", str);
      97                 :            :     }
      98                 :        760 :     *valuep = value;
      99                 :        760 :     return NULL;
     100                 :            : }
     101                 :            : 
     102                 :            : /* Parses 'str' as an 64-bit unsigned integer into '*valuep'.
     103                 :            :  *
     104                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
     105                 :            :  * error.  The caller is responsible for freeing the returned string. */
     106                 :            : char * OVS_WARN_UNUSED_RESULT
     107                 :      14584 : str_to_u64(const char *str, uint64_t *valuep)
     108                 :            : {
     109                 :            :     char *tail;
     110                 :            :     uint64_t value;
     111                 :            : 
     112         [ -  + ]:      14584 :     if (!str[0]) {
     113                 :          0 :         return xstrdup("missing required numeric argument");
     114                 :            :     }
     115                 :            : 
     116                 :      14584 :     errno = 0;
     117                 :      14584 :     value = strtoull(str, &tail, 0);
     118 [ +  - ][ +  - ]:      14584 :     if (errno == EINVAL || errno == ERANGE || *tail) {
                 [ -  + ]
     119                 :          0 :         return xasprintf("invalid numeric format %s", str);
     120                 :            :     }
     121                 :      14584 :     *valuep = value;
     122                 :      14584 :     return NULL;
     123                 :            : }
     124                 :            : 
     125                 :            : /* Parses 'str' as an 64-bit unsigned integer in network byte order into
     126                 :            :  * '*valuep'.
     127                 :            :  *
     128                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
     129                 :            :  * error.  The caller is responsible for freeing the returned string. */
     130                 :            : char * OVS_WARN_UNUSED_RESULT
     131                 :      14573 : str_to_be64(const char *str, ovs_be64 *valuep)
     132                 :            : {
     133                 :      14573 :     uint64_t value = 0;
     134                 :            :     char *error;
     135                 :            : 
     136                 :      14573 :     error = str_to_u64(str, &value);
     137         [ +  - ]:      14573 :     if (!error) {
     138                 :      14573 :         *valuep = htonll(value);
     139                 :            :     }
     140                 :      14573 :     return error;
     141                 :            : }
     142                 :            : 
     143                 :            : /* Parses 'str' as an Ethernet address into 'mac'.
     144                 :            :  *
     145                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
     146                 :            :  * error.  The caller is responsible for freeing the returned string. */
     147                 :            : char * OVS_WARN_UNUSED_RESULT
     148                 :         19 : str_to_mac(const char *str, struct eth_addr *mac)
     149                 :            : {
     150         [ -  + ]:         19 :     if (!ovs_scan(str, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(*mac))) {
     151                 :          0 :         return xasprintf("invalid mac address %s", str);
     152                 :            :     }
     153                 :         19 :     return NULL;
     154                 :            : }
     155                 :            : 
     156                 :            : /* Parses 'str' as an IP address into '*ip'.
     157                 :            :  *
     158                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
     159                 :            :  * error.  The caller is responsible for freeing the returned string. */
     160                 :            : char * OVS_WARN_UNUSED_RESULT
     161                 :          6 : str_to_ip(const char *str, ovs_be32 *ip)
     162                 :            : {
     163                 :            :     struct in_addr in_addr;
     164                 :            : 
     165         [ -  + ]:          6 :     if (lookup_ip(str, &in_addr)) {
     166                 :          0 :         return xasprintf("%s: could not convert to IP address", str);
     167                 :            :     }
     168                 :          6 :     *ip = in_addr.s_addr;
     169                 :          6 :     return NULL;
     170                 :            : }
     171                 :            : 
     172                 :            : /* Parses 'str' as a conntrack helper into 'alg'.
     173                 :            :  *
     174                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
     175                 :            :  * error.  The caller is responsible for freeing the returned string. */
     176                 :            : char * OVS_WARN_UNUSED_RESULT
     177                 :         10 : str_to_connhelper(const char *str, uint16_t *alg)
     178                 :            : {
     179         [ +  - ]:         10 :     if (!strcmp(str, "ftp")) {
     180                 :         10 :         *alg = IPPORT_FTP;
     181                 :         10 :         return NULL;
     182                 :            :     }
     183                 :          0 :     return xasprintf("invalid conntrack helper \"%s\"", str);
     184                 :            : }
     185                 :            : 
     186                 :            : struct protocol {
     187                 :            :     const char *name;
     188                 :            :     uint16_t dl_type;
     189                 :            :     uint8_t nw_proto;
     190                 :            : };
     191                 :            : 
     192                 :            : static bool
     193                 :      43774 : parse_protocol(const char *name, const struct protocol **p_out)
     194                 :            : {
     195                 :            :     static const struct protocol protocols[] = {
     196                 :            :         { "ip", ETH_TYPE_IP, 0 },
     197                 :            :         { "ipv4", ETH_TYPE_IP, 0 },
     198                 :            :         { "ip4", ETH_TYPE_IP, 0 },
     199                 :            :         { "arp", ETH_TYPE_ARP, 0 },
     200                 :            :         { "icmp", ETH_TYPE_IP, IPPROTO_ICMP },
     201                 :            :         { "tcp", ETH_TYPE_IP, IPPROTO_TCP },
     202                 :            :         { "udp", ETH_TYPE_IP, IPPROTO_UDP },
     203                 :            :         { "sctp", ETH_TYPE_IP, IPPROTO_SCTP },
     204                 :            :         { "ipv6", ETH_TYPE_IPV6, 0 },
     205                 :            :         { "ip6", ETH_TYPE_IPV6, 0 },
     206                 :            :         { "icmp6", ETH_TYPE_IPV6, IPPROTO_ICMPV6 },
     207                 :            :         { "tcp6", ETH_TYPE_IPV6, IPPROTO_TCP },
     208                 :            :         { "udp6", ETH_TYPE_IPV6, IPPROTO_UDP },
     209                 :            :         { "sctp6", ETH_TYPE_IPV6, IPPROTO_SCTP },
     210                 :            :         { "rarp", ETH_TYPE_RARP, 0},
     211                 :            :         { "mpls", ETH_TYPE_MPLS, 0 },
     212                 :            :         { "mplsm", ETH_TYPE_MPLS_MCAST, 0 },
     213                 :            :     };
     214                 :            :     const struct protocol *p;
     215                 :            : 
     216         [ +  + ]:     776163 :     for (p = protocols; p < &protocols[ARRAY_SIZE(protocols)]; p++) {
     217         [ +  + ]:     733324 :         if (!strcmp(p->name, name)) {
     218                 :        935 :             *p_out = p;
     219                 :        935 :             return true;
     220                 :            :         }
     221                 :            :     }
     222                 :      42839 :     *p_out = NULL;
     223                 :      42839 :     return false;
     224                 :            : }
     225                 :            : 
     226                 :            : /* Parses 's' as the (possibly masked) value of field 'mf', and updates
     227                 :            :  * 'match' appropriately.  Restricts the set of usable protocols to ones
     228                 :            :  * supporting the parsed field.
     229                 :            :  *
     230                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
     231                 :            :  * error.  The caller is responsible for freeing the returned string. */
     232                 :            : static char * OVS_WARN_UNUSED_RESULT
     233                 :      22223 : parse_field(const struct mf_field *mf, const char *s, struct match *match,
     234                 :            :             enum ofputil_protocol *usable_protocols)
     235                 :            : {
     236                 :            :     union mf_value value, mask;
     237                 :            :     char *error;
     238                 :            : 
     239         [ +  + ]:      22223 :     if (!*s) {
     240                 :            :         /* If there's no string, we're just trying to match on the
     241                 :            :          * existence of the field, so use a no-op value. */
     242                 :          9 :         s = "0/0";
     243                 :            :     }
     244                 :            : 
     245                 :      22223 :     error = mf_parse(mf, s, &value, &mask);
     246         [ +  + ]:      22223 :     if (!error) {
     247                 :      22193 :         *usable_protocols &= mf_set(mf, &value, &mask, match, &error);
     248                 :            :     }
     249                 :      22223 :     return error;
     250                 :            : }
     251                 :            : 
     252                 :            : static char *
     253                 :      21868 : extract_actions(char *s)
     254                 :            : {
     255                 :      21868 :     s = strstr(s, "action");
     256         [ +  - ]:      21868 :     if (s) {
     257                 :      21868 :         *s = '\0';
     258                 :      21868 :         s = strchr(s + 1, '=');
     259         [ +  - ]:      21868 :         return s ? s + 1 : NULL;
     260                 :            :     } else {
     261                 :          0 :         return NULL;
     262                 :            :     }
     263                 :            : }
     264                 :            : 
     265                 :            : 
     266                 :            : static char * OVS_WARN_UNUSED_RESULT
     267                 :      22990 : parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
     268                 :            :                 enum ofputil_protocol *usable_protocols)
     269                 :            : {
     270                 :            :     enum {
     271                 :            :         F_OUT_PORT = 1 << 0,
     272                 :            :         F_ACTIONS = 1 << 1,
     273                 :            :         F_IMPORTANCE = 1 << 2,
     274                 :            :         F_TIMEOUT = 1 << 3,
     275                 :            :         F_PRIORITY = 1 << 4,
     276                 :            :         F_FLAGS = 1 << 5,
     277                 :            :     } fields;
     278                 :      22990 :     char *act_str = NULL;
     279                 :            :     char *name, *value;
     280                 :            : 
     281                 :      22990 :     *usable_protocols = OFPUTIL_P_ANY;
     282                 :            : 
     283         [ +  + ]:      22990 :     if (command == -2) {
     284                 :            :         size_t len;
     285                 :            : 
     286                 :      10717 :         string += strspn(string, " \t\r\n");   /* Skip white space. */
     287                 :      10717 :         len = strcspn(string, ", \t\r\n"); /* Get length of the first token. */
     288                 :            : 
     289         [ +  + ]:      10717 :         if (!strncmp(string, "add", len)) {
     290                 :         37 :             command = OFPFC_ADD;
     291         [ +  + ]:      10680 :         } else if (!strncmp(string, "delete", len)) {
     292                 :          8 :             command = OFPFC_DELETE;
     293         [ +  + ]:      10672 :         } else if (!strncmp(string, "delete_strict", len)) {
     294                 :          2 :             command = OFPFC_DELETE_STRICT;
     295         [ +  + ]:      10670 :         } else if (!strncmp(string, "modify", len)) {
     296                 :          4 :             command = OFPFC_MODIFY;
     297         [ +  + ]:      10666 :         } else if (!strncmp(string, "modify_strict", len)) {
     298                 :          2 :             command = OFPFC_MODIFY_STRICT;
     299                 :            :         } else {
     300                 :      10664 :             len = 0;
     301                 :      10664 :             command = OFPFC_ADD;
     302                 :            :         }
     303                 :      10717 :         string += len;
     304                 :            :     }
     305                 :            : 
     306   [ +  +  +  +  :      22990 :     switch (command) {
                +  +  - ]
     307                 :            :     case -1:
     308                 :        403 :         fields = F_OUT_PORT;
     309                 :        403 :         break;
     310                 :            : 
     311                 :            :     case OFPFC_ADD:
     312                 :      21827 :         fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS | F_IMPORTANCE;
     313                 :      21827 :         break;
     314                 :            : 
     315                 :            :     case OFPFC_DELETE:
     316                 :        691 :         fields = F_OUT_PORT;
     317                 :        691 :         break;
     318                 :            : 
     319                 :            :     case OFPFC_DELETE_STRICT:
     320                 :         28 :         fields = F_OUT_PORT | F_PRIORITY;
     321                 :         28 :         break;
     322                 :            : 
     323                 :            :     case OFPFC_MODIFY:
     324                 :         39 :         fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS;
     325                 :         39 :         break;
     326                 :            : 
     327                 :            :     case OFPFC_MODIFY_STRICT:
     328                 :          2 :         fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS;
     329                 :          2 :         break;
     330                 :            : 
     331                 :            :     default:
     332                 :          0 :         OVS_NOT_REACHED();
     333                 :            :     }
     334                 :            : 
     335                 :      22990 :     *fm = (struct ofputil_flow_mod) {
     336                 :            :         .match = MATCH_CATCHALL_INITIALIZER,
     337                 :            :         .priority = OFP_DEFAULT_PRIORITY,
     338                 :            :         .table_id = 0xff,
     339                 :            :         .command = command,
     340                 :            :         .buffer_id = UINT32_MAX,
     341                 :            :         .out_port = OFPP_ANY,
     342                 :            :         .out_group = OFPG_ANY,
     343                 :            :     };
     344                 :            :     /* For modify, by default, don't update the cookie. */
     345 [ +  + ][ +  + ]:      22990 :     if (command == OFPFC_MODIFY || command == OFPFC_MODIFY_STRICT) {
     346                 :         41 :         fm->new_cookie = OVS_BE64_MAX;
     347                 :            :     }
     348                 :            : 
     349         [ +  + ]:      22990 :     if (fields & F_ACTIONS) {
     350                 :      21868 :         act_str = extract_actions(string);
     351         [ -  + ]:      21868 :         if (!act_str) {
     352                 :          0 :             return xstrdup("must specify an action");
     353                 :            :         }
     354                 :            :     }
     355                 :            : 
     356         [ +  + ]:      63038 :     while (ofputil_parse_key_value(&string, &name, &value)) {
     357                 :            :         const struct protocol *p;
     358                 :      40080 :         char *error = NULL;
     359                 :            : 
     360         [ +  + ]:      40080 :         if (parse_protocol(name, &p)) {
     361                 :        923 :             match_set_dl_type(&fm->match, htons(p->dl_type));
     362         [ +  + ]:        923 :             if (p->nw_proto) {
     363                 :        923 :                 match_set_nw_proto(&fm->match, p->nw_proto);
     364                 :            :             }
     365 [ +  + ][ +  + ]:      39157 :         } else if (fields & F_FLAGS && !strcmp(name, "send_flow_rem")) {
     366                 :         39 :             fm->flags |= OFPUTIL_FF_SEND_FLOW_REM;
     367 [ +  + ][ +  + ]:      39118 :         } else if (fields & F_FLAGS && !strcmp(name, "check_overlap")) {
     368                 :          2 :             fm->flags |= OFPUTIL_FF_CHECK_OVERLAP;
     369 [ +  + ][ -  + ]:      39116 :         } else if (fields & F_FLAGS && !strcmp(name, "reset_counts")) {
     370                 :          0 :             fm->flags |= OFPUTIL_FF_RESET_COUNTS;
     371                 :          0 :             *usable_protocols &= OFPUTIL_P_OF12_UP;
     372 [ +  + ][ -  + ]:      39116 :         } else if (fields & F_FLAGS && !strcmp(name, "no_packet_counts")) {
     373                 :          0 :             fm->flags |= OFPUTIL_FF_NO_PKT_COUNTS;
     374                 :          0 :             *usable_protocols &= OFPUTIL_P_OF13_UP;
     375 [ +  + ][ -  + ]:      39116 :         } else if (fields & F_FLAGS && !strcmp(name, "no_byte_counts")) {
     376                 :          0 :             fm->flags |= OFPUTIL_FF_NO_BYT_COUNTS;
     377                 :          0 :             *usable_protocols &= OFPUTIL_P_OF13_UP;
     378         [ +  - ]:      39116 :         } else if (!strcmp(name, "no_readonly_table")
     379         [ +  - ]:      39116 :                    || !strcmp(name, "allow_hidden_fields")) {
     380                 :            :              /* ignore these fields. */
     381         [ +  + ]:      39116 :         } else if (mf_from_name(name)) {
     382                 :      22223 :             error = parse_field(mf_from_name(name), value, &fm->match,
     383                 :            :                                 usable_protocols);
     384                 :            :         } else {
     385         [ -  + ]:      16893 :             if (!*value) {
     386                 :         32 :                 return xasprintf("field %s missing value", name);
     387                 :            :             }
     388                 :            : 
     389         [ +  + ]:      16893 :             if (!strcmp(name, "table")) {
     390                 :       1078 :                 error = str_to_u8(value, "table", &fm->table_id);
     391         [ +  - ]:       1078 :                 if (fm->table_id != 0xff) {
     392                 :       1078 :                     *usable_protocols &= OFPUTIL_P_TID;
     393                 :            :                 }
     394 [ +  + ][ +  + ]:      15815 :             } else if (fields & F_OUT_PORT && !strcmp(name, "out_port")) {
     395         [ -  + ]:         10 :                 if (!ofputil_port_from_string(value, &fm->out_port)) {
     396                 :          0 :                     error = xasprintf("%s is not a valid OpenFlow port",
     397                 :            :                                       value);
     398                 :            :                 }
     399 [ +  + ][ +  + ]:      15805 :             } else if (fields & F_OUT_PORT && !strcmp(name, "out_group")) {
     400                 :          8 :                 *usable_protocols &= OFPUTIL_P_OF11_UP;
     401         [ -  + ]:          8 :                 if (!ofputil_group_from_string(value, &fm->out_group)) {
     402                 :          0 :                     error = xasprintf("%s is not a valid OpenFlow group",
     403                 :            :                                       value);
     404                 :            :                 }
     405 [ +  + ][ +  + ]:      16690 :             } else if (fields & F_PRIORITY && !strcmp(name, "priority")) {
     406                 :        893 :                 uint16_t priority = 0;
     407                 :            : 
     408                 :        893 :                 error = str_to_u16(value, name, &priority);
     409                 :        893 :                 fm->priority = priority;
     410 [ +  + ][ +  + ]:      14904 :             } else if (fields & F_TIMEOUT && !strcmp(name, "idle_timeout")) {
     411                 :         80 :                 error = str_to_u16(value, name, &fm->idle_timeout);
     412 [ +  + ][ +  + ]:      14824 :             } else if (fields & F_TIMEOUT && !strcmp(name, "hard_timeout")) {
     413                 :         18 :                 error = str_to_u16(value, name, &fm->hard_timeout);
     414 [ +  + ][ +  + ]:      14806 :             } else if (fields & F_IMPORTANCE && !strcmp(name, "importance")) {
     415                 :         32 :                 error = str_to_u16(value, name, &fm->importance);
     416         [ +  + ]:      14774 :             } else if (!strcmp(name, "cookie")) {
     417                 :      14550 :                 char *mask = strchr(value, '/');
     418                 :            : 
     419         [ +  + ]:      14550 :                 if (mask) {
     420                 :            :                     /* A mask means we're searching for a cookie. */
     421         [ -  + ]:         23 :                     if (command == OFPFC_ADD) {
     422                 :          0 :                         return xstrdup("flow additions cannot use "
     423                 :            :                                        "a cookie mask");
     424                 :            :                     }
     425                 :         23 :                     *mask = '\0';
     426                 :         23 :                     error = str_to_be64(value, &fm->cookie);
     427         [ -  + ]:         23 :                     if (error) {
     428                 :          0 :                         return error;
     429                 :            :                     }
     430                 :         23 :                     error = str_to_be64(mask + 1, &fm->cookie_mask);
     431                 :            : 
     432                 :            :                     /* Matching of the cookie is only supported through NXM or
     433                 :            :                      * OF1.1+. */
     434         [ +  - ]:         23 :                     if (fm->cookie_mask != htonll(0)) {
     435                 :         23 :                         *usable_protocols &= OFPUTIL_P_NXM_OF11_UP;
     436                 :            :                     }
     437                 :            :                 } else {
     438                 :            :                     /* No mask means that the cookie is being set. */
     439 [ +  + ][ -  + ]:      14527 :                     if (command != OFPFC_ADD && command != OFPFC_MODIFY
     440         [ #  # ]:          0 :                         && command != OFPFC_MODIFY_STRICT) {
     441                 :          0 :                         return xstrdup("cannot set cookie");
     442                 :            :                     }
     443                 :      14527 :                     error = str_to_be64(value, &fm->new_cookie);
     444                 :      14550 :                     fm->modify_cookie = true;
     445                 :            :                 }
     446         [ +  + ]:        224 :             } else if (!strcmp(name, "duration")
     447         [ +  + ]:        168 :                        || !strcmp(name, "n_packets")
     448         [ +  + ]:        112 :                        || !strcmp(name, "n_bytes")
     449         [ -  + ]:         56 :                        || !strcmp(name, "idle_age")
     450         [ #  # ]:          0 :                        || !strcmp(name, "hard_age")) {
     451                 :            :                 /* Ignore these, so that users can feed the output of
     452                 :            :                  * "ovs-ofctl dump-flows" back into commands that parse
     453                 :            :                  * flows. */
     454                 :            :             } else {
     455                 :          0 :                 error = xasprintf("unknown keyword %s", name);
     456                 :            :             }
     457                 :            :         }
     458                 :            : 
     459         [ +  + ]:      40080 :         if (error) {
     460                 :      40080 :             return error;
     461                 :            :         }
     462                 :            :     }
     463                 :            :     /* Check for usable protocol interdependencies between match fields. */
     464         [ +  + ]:      22958 :     if (fm->match.flow.dl_type == htons(ETH_TYPE_IPV6)) {
     465                 :        130 :         const struct flow_wildcards *wc = &fm->match.wc;
     466                 :            :         /* Only NXM and OXM support matching L3 and L4 fields within IPv6.
     467                 :            :          *
     468                 :            :          * (IPv6 specific fields as well as arp_sha, arp_tha, nw_frag, and
     469                 :            :          *  nw_ttl are covered elsewhere so they don't need to be included in
     470                 :            :          *  this test too.)
     471                 :            :          */
     472 [ +  + ][ +  + ]:        130 :         if (wc->masks.nw_proto || wc->masks.nw_tos
     473 [ +  - ][ -  + ]:         47 :             || wc->masks.tp_src || wc->masks.tp_dst) {
     474                 :         83 :             *usable_protocols &= OFPUTIL_P_NXM_OXM_ANY;
     475                 :            :         }
     476                 :            :     }
     477 [ +  + ][ +  + ]:      22958 :     if (!fm->cookie_mask && fm->new_cookie == OVS_BE64_MAX
     478 [ +  + ][ +  - ]:         28 :         && (command == OFPFC_MODIFY || command == OFPFC_MODIFY_STRICT)) {
     479                 :            :         /* On modifies without a mask, we are supposed to add a flow if
     480                 :            :          * one does not exist.  If a cookie wasn't been specified, use a
     481                 :            :          * default of zero. */
     482                 :         28 :         fm->new_cookie = htonll(0);
     483                 :            :     }
     484         [ +  + ]:      22958 :     if (fields & F_ACTIONS) {
     485                 :            :         enum ofputil_protocol action_usable_protocols;
     486                 :            :         struct ofpbuf ofpacts;
     487                 :            :         char *error;
     488                 :            : 
     489                 :      21839 :         ofpbuf_init(&ofpacts, 32);
     490                 :      21839 :         error = ofpacts_parse_instructions(act_str, &ofpacts,
     491                 :            :                                            &action_usable_protocols);
     492                 :      21839 :         *usable_protocols &= action_usable_protocols;
     493         [ +  + ]:      21839 :         if (!error) {
     494                 :            :             enum ofperr err;
     495                 :            : 
     496                 :      21824 :             err = ofpacts_check(ofpacts.data, ofpacts.size, &fm->match.flow,
     497                 :      21824 :                                 OFPP_MAX, fm->table_id, 255, usable_protocols);
     498 [ +  + ][ +  + ]:      21824 :             if (!err && !*usable_protocols) {
     499                 :          4 :                 err = OFPERR_OFPBAC_MATCH_INCONSISTENT;
     500                 :            :             }
     501         [ +  + ]:      21824 :             if (err) {
     502                 :         15 :                 error = xasprintf("actions are invalid with specified match "
     503                 :            :                                   "(%s)", ofperr_to_string(err));
     504                 :            :             }
     505                 :            : 
     506                 :            :         }
     507         [ +  + ]:      21839 :         if (error) {
     508                 :         30 :             ofpbuf_uninit(&ofpacts);
     509                 :         30 :             return error;
     510                 :            :         }
     511                 :            : 
     512                 :      21809 :         fm->ofpacts_len = ofpacts.size;
     513                 :      21809 :         fm->ofpacts = ofpbuf_steal_data(&ofpacts);
     514                 :            :     } else {
     515                 :       1119 :         fm->ofpacts_len = 0;
     516                 :       1119 :         fm->ofpacts = NULL;
     517                 :            :     }
     518                 :            : 
     519                 :      22990 :     return NULL;
     520                 :            : }
     521                 :            : 
     522                 :            : /* Convert 'str_' (as described in the Flow Syntax section of the ovs-ofctl man
     523                 :            :  * page) into 'fm' for sending the specified flow_mod 'command' to a switch.
     524                 :            :  * Returns the set of usable protocols in '*usable_protocols'.
     525                 :            :  *
     526                 :            :  * To parse syntax for an OFPT_FLOW_MOD (or NXT_FLOW_MOD), use an OFPFC_*
     527                 :            :  * constant for 'command'.  To parse syntax for an OFPST_FLOW or
     528                 :            :  * OFPST_AGGREGATE (or NXST_FLOW or NXST_AGGREGATE), use -1 for 'command'.
     529                 :            :  *
     530                 :            :  * If 'command' is given as -2, 'str_' may begin with a command name ("add",
     531                 :            :  * "modify", "delete", "modify_strict", or "delete_strict").  A missing command
     532                 :            :  * name is treated as "add".
     533                 :            :  *
     534                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
     535                 :            :  * error.  The caller is responsible for freeing the returned string. */
     536                 :            : char * OVS_WARN_UNUSED_RESULT
     537                 :      22990 : parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
     538                 :            :               enum ofputil_protocol *usable_protocols)
     539                 :            : {
     540                 :      22990 :     char *string = xstrdup(str_);
     541                 :            :     char *error;
     542                 :            : 
     543                 :      22990 :     error = parse_ofp_str__(fm, command, string, usable_protocols);
     544         [ +  + ]:      22990 :     if (error) {
     545                 :         62 :         fm->ofpacts = NULL;
     546                 :         62 :         fm->ofpacts_len = 0;
     547                 :            :     }
     548                 :            : 
     549                 :      22990 :     free(string);
     550                 :      22990 :     return error;
     551                 :            : }
     552                 :            : 
     553                 :            : static char * OVS_WARN_UNUSED_RESULT
     554                 :          0 : parse_ofp_meter_mod_str__(struct ofputil_meter_mod *mm, char *string,
     555                 :            :                           struct ofpbuf *bands, int command,
     556                 :            :                           enum ofputil_protocol *usable_protocols)
     557                 :            : {
     558                 :            :     enum {
     559                 :            :         F_METER = 1 << 0,
     560                 :            :         F_FLAGS = 1 << 1,
     561                 :            :         F_BANDS = 1 << 2,
     562                 :            :     } fields;
     563                 :          0 :     char *save_ptr = NULL;
     564                 :          0 :     char *band_str = NULL;
     565                 :            :     char *name;
     566                 :            : 
     567                 :            :     /* Meters require at least OF 1.3. */
     568                 :          0 :     *usable_protocols = OFPUTIL_P_OF13_UP;
     569                 :            : 
     570   [ #  #  #  #  :          0 :     switch (command) {
                      # ]
     571                 :            :     case -1:
     572                 :          0 :         fields = F_METER;
     573                 :          0 :         break;
     574                 :            : 
     575                 :            :     case OFPMC13_ADD:
     576                 :          0 :         fields = F_METER | F_FLAGS | F_BANDS;
     577                 :          0 :         break;
     578                 :            : 
     579                 :            :     case OFPMC13_DELETE:
     580                 :          0 :         fields = F_METER;
     581                 :          0 :         break;
     582                 :            : 
     583                 :            :     case OFPMC13_MODIFY:
     584                 :          0 :         fields = F_METER | F_FLAGS | F_BANDS;
     585                 :          0 :         break;
     586                 :            : 
     587                 :            :     default:
     588                 :          0 :         OVS_NOT_REACHED();
     589                 :            :     }
     590                 :            : 
     591                 :          0 :     mm->command = command;
     592                 :          0 :     mm->meter.meter_id = 0;
     593                 :          0 :     mm->meter.flags = 0;
     594         [ #  # ]:          0 :     if (fields & F_BANDS) {
     595                 :          0 :         band_str = strstr(string, "band");
     596         [ #  # ]:          0 :         if (!band_str) {
     597                 :          0 :             return xstrdup("must specify bands");
     598                 :            :         }
     599                 :          0 :         *band_str = '\0';
     600                 :            : 
     601                 :          0 :         band_str = strchr(band_str + 1, '=');
     602         [ #  # ]:          0 :         if (!band_str) {
     603                 :          0 :             return xstrdup("must specify bands");
     604                 :            :         }
     605                 :            : 
     606                 :          0 :         band_str++;
     607                 :            :     }
     608         [ #  # ]:          0 :     for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name;
     609                 :          0 :          name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) {
     610                 :            : 
     611 [ #  # ][ #  # ]:          0 :         if (fields & F_FLAGS && !strcmp(name, "kbps")) {
     612                 :          0 :             mm->meter.flags |= OFPMF13_KBPS;
     613 [ #  # ][ #  # ]:          0 :         } else if (fields & F_FLAGS && !strcmp(name, "pktps")) {
     614                 :          0 :             mm->meter.flags |= OFPMF13_PKTPS;
     615 [ #  # ][ #  # ]:          0 :         } else if (fields & F_FLAGS && !strcmp(name, "burst")) {
     616                 :          0 :             mm->meter.flags |= OFPMF13_BURST;
     617 [ #  # ][ #  # ]:          0 :         } else if (fields & F_FLAGS && !strcmp(name, "stats")) {
     618                 :          0 :             mm->meter.flags |= OFPMF13_STATS;
     619                 :            :         } else {
     620                 :            :             char *value;
     621                 :            : 
     622                 :          0 :             value = strtok_r(NULL, ", \t\r\n", &save_ptr);
     623         [ #  # ]:          0 :             if (!value) {
     624                 :          0 :                 return xasprintf("field %s missing value", name);
     625                 :            :             }
     626                 :            : 
     627         [ #  # ]:          0 :             if (!strcmp(name, "meter")) {
     628         [ #  # ]:          0 :                 if (!strcmp(value, "all")) {
     629                 :          0 :                     mm->meter.meter_id = OFPM13_ALL;
     630         [ #  # ]:          0 :                 } else if (!strcmp(value, "controller")) {
     631                 :          0 :                     mm->meter.meter_id = OFPM13_CONTROLLER;
     632         [ #  # ]:          0 :                 } else if (!strcmp(value, "slowpath")) {
     633                 :          0 :                     mm->meter.meter_id = OFPM13_SLOWPATH;
     634                 :            :                 } else {
     635                 :          0 :                     char *error = str_to_u32(value, &mm->meter.meter_id);
     636         [ #  # ]:          0 :                     if (error) {
     637                 :          0 :                         return error;
     638                 :            :                     }
     639         [ #  # ]:          0 :                     if (mm->meter.meter_id > OFPM13_MAX
     640         [ #  # ]:          0 :                         || !mm->meter.meter_id) {
     641                 :          0 :                         return xasprintf("invalid value for %s", name);
     642                 :            :                     }
     643                 :            :                 }
     644                 :            :             } else {
     645                 :          0 :                 return xasprintf("unknown keyword %s", name);
     646                 :            :             }
     647                 :            :         }
     648                 :            :     }
     649 [ #  # ][ #  # ]:          0 :     if (fields & F_METER && !mm->meter.meter_id) {
     650                 :          0 :         return xstrdup("must specify 'meter'");
     651                 :            :     }
     652 [ #  # ][ #  # ]:          0 :     if (fields & F_FLAGS && !mm->meter.flags) {
     653                 :          0 :         return xstrdup("meter must specify either 'kbps' or 'pktps'");
     654                 :            :     }
     655                 :            : 
     656         [ #  # ]:          0 :     if (fields & F_BANDS) {
     657                 :          0 :         uint16_t n_bands = 0;
     658                 :          0 :         struct ofputil_meter_band *band = NULL;
     659                 :            :         int i;
     660                 :            : 
     661         [ #  # ]:          0 :         for (name = strtok_r(band_str, "=, \t\r\n", &save_ptr); name;
     662                 :          0 :              name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) {
     663                 :            : 
     664                 :            :             char *value;
     665                 :            : 
     666                 :          0 :             value = strtok_r(NULL, ", \t\r\n", &save_ptr);
     667         [ #  # ]:          0 :             if (!value) {
     668                 :          0 :                 return xasprintf("field %s missing value", name);
     669                 :            :             }
     670                 :            : 
     671         [ #  # ]:          0 :             if (!strcmp(name, "type")) {
     672                 :            :                 /* Start a new band */
     673                 :          0 :                 band = ofpbuf_put_zeros(bands, sizeof *band);
     674                 :          0 :                 n_bands++;
     675                 :            : 
     676         [ #  # ]:          0 :                 if (!strcmp(value, "drop")) {
     677                 :          0 :                     band->type = OFPMBT13_DROP;
     678         [ #  # ]:          0 :                 } else if (!strcmp(value, "dscp_remark")) {
     679                 :          0 :                     band->type = OFPMBT13_DSCP_REMARK;
     680                 :            :                 } else {
     681                 :          0 :                     return xasprintf("field %s unknown value %s", name, value);
     682                 :            :                 }
     683 [ #  # ][ #  # ]:          0 :             } else if (!band || !band->type) {
     684                 :          0 :                 return xstrdup("band must start with the 'type' keyword");
     685         [ #  # ]:          0 :             } else if (!strcmp(name, "rate")) {
     686                 :          0 :                 char *error = str_to_u32(value, &band->rate);
     687         [ #  # ]:          0 :                 if (error) {
     688                 :          0 :                     return error;
     689                 :            :                 }
     690         [ #  # ]:          0 :             } else if (!strcmp(name, "burst_size")) {
     691                 :          0 :                 char *error = str_to_u32(value, &band->burst_size);
     692         [ #  # ]:          0 :                 if (error) {
     693                 :          0 :                     return error;
     694                 :            :                 }
     695         [ #  # ]:          0 :             } else if (!strcmp(name, "prec_level")) {
     696                 :          0 :                 char *error = str_to_u8(value, name, &band->prec_level);
     697         [ #  # ]:          0 :                 if (error) {
     698                 :          0 :                     return error;
     699                 :            :                 }
     700                 :            :             } else {
     701                 :          0 :                 return xasprintf("unknown keyword %s", name);
     702                 :            :             }
     703                 :            :         }
     704                 :            :         /* validate bands */
     705         [ #  # ]:          0 :         if (!n_bands) {
     706                 :          0 :             return xstrdup("meter must have bands");
     707                 :            :         }
     708                 :            : 
     709                 :          0 :         mm->meter.n_bands = n_bands;
     710                 :          0 :         mm->meter.bands = ofpbuf_steal_data(bands);
     711                 :            : 
     712         [ #  # ]:          0 :         for (i = 0; i < n_bands; ++i) {
     713                 :          0 :             band = &mm->meter.bands[i];
     714                 :            : 
     715         [ #  # ]:          0 :             if (!band->type) {
     716                 :          0 :                 return xstrdup("band must have 'type'");
     717                 :            :             }
     718         [ #  # ]:          0 :             if (band->type == OFPMBT13_DSCP_REMARK) {
     719         [ #  # ]:          0 :                 if (!band->prec_level) {
     720                 :          0 :                     return xstrdup("'dscp_remark' band must have"
     721                 :            :                                    " 'prec_level'");
     722                 :            :                 }
     723                 :            :             } else {
     724         [ #  # ]:          0 :                 if (band->prec_level) {
     725                 :          0 :                     return xstrdup("Only 'dscp_remark' band may have"
     726                 :            :                                    " 'prec_level'");
     727                 :            :                 }
     728                 :            :             }
     729         [ #  # ]:          0 :             if (!band->rate) {
     730                 :          0 :                 return xstrdup("band must have 'rate'");
     731                 :            :             }
     732         [ #  # ]:          0 :             if (mm->meter.flags & OFPMF13_BURST) {
     733         [ #  # ]:          0 :                 if (!band->burst_size) {
     734                 :          0 :                     return xstrdup("band must have 'burst_size' "
     735                 :            :                                    "when 'burst' flag is set");
     736                 :            :                 }
     737                 :            :             } else {
     738         [ #  # ]:          0 :                 if (band->burst_size) {
     739                 :          0 :                     return xstrdup("band may have 'burst_size' only "
     740                 :            :                                    "when 'burst' flag is set");
     741                 :            :                 }
     742                 :            :             }
     743                 :            :         }
     744                 :            :     } else {
     745                 :          0 :         mm->meter.n_bands = 0;
     746                 :          0 :         mm->meter.bands = NULL;
     747                 :            :     }
     748                 :            : 
     749                 :          0 :     return NULL;
     750                 :            : }
     751                 :            : 
     752                 :            : /* Convert 'str_' (as described in the Flow Syntax section of the ovs-ofctl man
     753                 :            :  * page) into 'mm' for sending the specified meter_mod 'command' to a switch.
     754                 :            :  *
     755                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
     756                 :            :  * error.  The caller is responsible for freeing the returned string. */
     757                 :            : char * OVS_WARN_UNUSED_RESULT
     758                 :          0 : parse_ofp_meter_mod_str(struct ofputil_meter_mod *mm, const char *str_,
     759                 :            :                         int command, enum ofputil_protocol *usable_protocols)
     760                 :            : {
     761                 :            :     struct ofpbuf bands;
     762                 :            :     char *string;
     763                 :            :     char *error;
     764                 :            : 
     765                 :          0 :     ofpbuf_init(&bands, 64);
     766                 :          0 :     string = xstrdup(str_);
     767                 :            : 
     768                 :          0 :     error = parse_ofp_meter_mod_str__(mm, string, &bands, command,
     769                 :            :                                       usable_protocols);
     770                 :            : 
     771                 :          0 :     free(string);
     772                 :          0 :     ofpbuf_uninit(&bands);
     773                 :            : 
     774                 :          0 :     return error;
     775                 :            : }
     776                 :            : 
     777                 :            : static char * OVS_WARN_UNUSED_RESULT
     778                 :          4 : parse_flow_monitor_request__(struct ofputil_flow_monitor_request *fmr,
     779                 :            :                              const char *str_, char *string,
     780                 :            :                              enum ofputil_protocol *usable_protocols)
     781                 :            : {
     782                 :            :     static atomic_count id = ATOMIC_COUNT_INIT(0);
     783                 :            :     char *name, *value;
     784                 :            : 
     785                 :          4 :     fmr->id = atomic_count_inc(&id);
     786                 :            : 
     787                 :          4 :     fmr->flags = (NXFMF_INITIAL | NXFMF_ADD | NXFMF_DELETE | NXFMF_MODIFY
     788                 :            :                   | NXFMF_OWN | NXFMF_ACTIONS);
     789                 :          4 :     fmr->out_port = OFPP_NONE;
     790                 :          4 :     fmr->table_id = 0xff;
     791                 :          4 :     match_init_catchall(&fmr->match);
     792                 :            : 
     793         [ +  + ]:          6 :     while (ofputil_parse_key_value(&string, &name, &value)) {
     794                 :            :         const struct protocol *p;
     795                 :          2 :         char *error = NULL;
     796                 :            : 
     797         [ -  + ]:          2 :         if (!strcmp(name, "!initial")) {
     798                 :          0 :             fmr->flags &= ~NXFMF_INITIAL;
     799         [ -  + ]:          2 :         } else if (!strcmp(name, "!add")) {
     800                 :          0 :             fmr->flags &= ~NXFMF_ADD;
     801         [ -  + ]:          2 :         } else if (!strcmp(name, "!delete")) {
     802                 :          0 :             fmr->flags &= ~NXFMF_DELETE;
     803         [ -  + ]:          2 :         } else if (!strcmp(name, "!modify")) {
     804                 :          0 :             fmr->flags &= ~NXFMF_MODIFY;
     805         [ -  + ]:          2 :         } else if (!strcmp(name, "!actions")) {
     806                 :          0 :             fmr->flags &= ~NXFMF_ACTIONS;
     807         [ +  + ]:          2 :         } else if (!strcmp(name, "!own")) {
     808                 :          1 :             fmr->flags &= ~NXFMF_OWN;
     809         [ -  + ]:          1 :         } else if (parse_protocol(name, &p)) {
     810                 :          0 :             match_set_dl_type(&fmr->match, htons(p->dl_type));
     811         [ #  # ]:          0 :             if (p->nw_proto) {
     812                 :          0 :                 match_set_nw_proto(&fmr->match, p->nw_proto);
     813                 :            :             }
     814         [ -  + ]:          1 :         } else if (mf_from_name(name)) {
     815                 :          0 :             error = parse_field(mf_from_name(name), value, &fmr->match,
     816                 :            :                                 usable_protocols);
     817                 :            :         } else {
     818         [ -  + ]:          1 :             if (!*value) {
     819                 :          0 :                 return xasprintf("%s: field %s missing value", str_, name);
     820                 :            :             }
     821                 :            : 
     822         [ -  + ]:          1 :             if (!strcmp(name, "table")) {
     823                 :          0 :                 error = str_to_u8(value, "table", &fmr->table_id);
     824         [ +  - ]:          1 :             } else if (!strcmp(name, "out_port")) {
     825                 :          1 :                 fmr->out_port = u16_to_ofp(atoi(value));
     826                 :            :             } else {
     827                 :          0 :                 return xasprintf("%s: unknown keyword %s", str_, name);
     828                 :            :             }
     829                 :            :         }
     830                 :            : 
     831         [ -  + ]:          2 :         if (error) {
     832                 :          2 :             return error;
     833                 :            :         }
     834                 :            :     }
     835                 :          4 :     return NULL;
     836                 :            : }
     837                 :            : 
     838                 :            : /* Convert 'str_' (as described in the documentation for the "monitor" command
     839                 :            :  * in the ovs-ofctl man page) into 'fmr'.
     840                 :            :  *
     841                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
     842                 :            :  * error.  The caller is responsible for freeing the returned string. */
     843                 :            : char * OVS_WARN_UNUSED_RESULT
     844                 :          4 : parse_flow_monitor_request(struct ofputil_flow_monitor_request *fmr,
     845                 :            :                            const char *str_,
     846                 :            :                            enum ofputil_protocol *usable_protocols)
     847                 :            : {
     848                 :          4 :     char *string = xstrdup(str_);
     849                 :          4 :     char *error = parse_flow_monitor_request__(fmr, str_, string,
     850                 :            :                                                usable_protocols);
     851                 :          4 :     free(string);
     852                 :          4 :     return error;
     853                 :            : }
     854                 :            : 
     855                 :            : /* Parses 'string' as an OFPT_FLOW_MOD or NXT_FLOW_MOD with command 'command'
     856                 :            :  * (one of OFPFC_*) into 'fm'.
     857                 :            :  *
     858                 :            :  * If 'command' is given as -2, 'string' may begin with a command name ("add",
     859                 :            :  * "modify", "delete", "modify_strict", or "delete_strict").  A missing command
     860                 :            :  * name is treated as "add".
     861                 :            :  *
     862                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
     863                 :            :  * error.  The caller is responsible for freeing the returned string. */
     864                 :            : char * OVS_WARN_UNUSED_RESULT
     865                 :      12293 : parse_ofp_flow_mod_str(struct ofputil_flow_mod *fm, const char *string,
     866                 :            :                        int command,
     867                 :            :                        enum ofputil_protocol *usable_protocols)
     868                 :            : {
     869                 :      12293 :     char *error = parse_ofp_str(fm, command, string, usable_protocols);
     870                 :            : 
     871         [ +  + ]:      12293 :     if (!error) {
     872                 :            :         /* Normalize a copy of the match.  This ensures that non-normalized
     873                 :            :          * flows get logged but doesn't affect what gets sent to the switch, so
     874                 :            :          * that the switch can do whatever it likes with the flow. */
     875                 :      12231 :         struct match match_copy = fm->match;
     876                 :      12231 :         ofputil_normalize_match(&match_copy);
     877                 :            :     }
     878                 :            : 
     879                 :      12293 :     return error;
     880                 :            : }
     881                 :            : 
     882                 :            : /* Convert 'setting' (as described for the "mod-table" command
     883                 :            :  * in ovs-ofctl man page) into 'tm->table_vacancy->vacancy_up' and
     884                 :            :  * 'tm->table_vacancy->vacancy_down' threshold values.
     885                 :            :  * For the two threshold values, value of vacancy_up is always greater
     886                 :            :  * than value of vacancy_down.
     887                 :            :  *
     888                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
     889                 :            :  * error.  The caller is responsible for freeing the returned string. */
     890                 :            : char * OVS_WARN_UNUSED_RESULT
     891                 :          3 : parse_ofp_table_vacancy(struct ofputil_table_mod *tm, const char *setting)
     892                 :            : {
     893                 :          3 :     char *save_ptr = NULL;
     894                 :            :     char *vac_up, *vac_down;
     895                 :          3 :     char *value = xstrdup(setting);
     896                 :            :     char *ret_msg;
     897                 :            :     int vacancy_up, vacancy_down;
     898                 :            : 
     899                 :          3 :     strtok_r(value, ":", &save_ptr);
     900                 :          3 :     vac_down = strtok_r(NULL, ",", &save_ptr);
     901         [ -  + ]:          3 :     if (!vac_down) {
     902                 :          0 :         ret_msg = xasprintf("Vacancy down value missing");
     903                 :          0 :         goto exit;
     904                 :            :     }
     905 [ +  - ][ +  - ]:          3 :     if (!str_to_int(vac_down, 0, &vacancy_down) ||
     906         [ -  + ]:          3 :         vacancy_down < 0 || vacancy_down > 100) {
     907                 :          0 :         ret_msg = xasprintf("Invalid vacancy down value \"%s\"", vac_down);
     908                 :          0 :         goto exit;
     909                 :            :     }
     910                 :          3 :     vac_up = strtok_r(NULL, ",", &save_ptr);
     911         [ -  + ]:          3 :     if (!vac_up) {
     912                 :          0 :         ret_msg = xasprintf("Vacancy up value missing");
     913                 :          0 :         goto exit;
     914                 :            :     }
     915 [ +  - ][ +  - ]:          3 :     if (!str_to_int(vac_up, 0, &vacancy_up) ||
     916         [ -  + ]:          3 :         vacancy_up < 0 || vacancy_up > 100) {
     917                 :          0 :         ret_msg = xasprintf("Invalid vacancy up value \"%s\"", vac_up);
     918                 :          0 :         goto exit;
     919                 :            :     }
     920         [ -  + ]:          3 :     if (vacancy_down > vacancy_up) {
     921                 :          0 :         ret_msg = xasprintf("Invalid vacancy range, vacancy up should be "
     922                 :            :                             "greater than vacancy down (%s)",
     923                 :            :                             ofperr_to_string(OFPERR_OFPBPC_BAD_VALUE));
     924                 :          0 :         goto exit;
     925                 :            :     }
     926                 :            : 
     927                 :          3 :     free(value);
     928                 :          3 :     tm->table_vacancy.vacancy_down = vacancy_down;
     929                 :          3 :     tm->table_vacancy.vacancy_up = vacancy_up;
     930                 :          3 :     return NULL;
     931                 :            : 
     932                 :            : exit:
     933                 :          0 :     free(value);
     934                 :          3 :     return ret_msg;
     935                 :            : }
     936                 :            : 
     937                 :            : /* Convert 'table_id' and 'setting' (as described for the "mod-table" command
     938                 :            :  * in the ovs-ofctl man page) into 'tm' for sending a table_mod command to a
     939                 :            :  * switch.
     940                 :            :  *
     941                 :            :  * Stores a bitmap of the OpenFlow versions that are usable for 'tm' into
     942                 :            :  * '*usable_versions'.
     943                 :            :  *
     944                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
     945                 :            :  * error.  The caller is responsible for freeing the returned string. */
     946                 :            : char * OVS_WARN_UNUSED_RESULT
     947                 :         14 : parse_ofp_table_mod(struct ofputil_table_mod *tm, const char *table_id,
     948                 :            :                     const char *setting, uint32_t *usable_versions)
     949                 :            : {
     950                 :         14 :     *usable_versions = 0;
     951         [ +  + ]:         14 :     if (!strcasecmp(table_id, "all")) {
     952                 :          7 :         tm->table_id = OFPTT_ALL;
     953                 :            :     } else {
     954                 :          7 :         char *error = str_to_u8(table_id, "table_id", &tm->table_id);
     955         [ -  + ]:          7 :         if (error) {
     956                 :          0 :             return error;
     957                 :            :         }
     958                 :            :     }
     959                 :            : 
     960                 :         14 :     tm->miss = OFPUTIL_TABLE_MISS_DEFAULT;
     961                 :         14 :     tm->eviction = OFPUTIL_TABLE_EVICTION_DEFAULT;
     962                 :         14 :     tm->eviction_flags = UINT32_MAX;
     963                 :         14 :     tm->vacancy = OFPUTIL_TABLE_VACANCY_DEFAULT;
     964                 :         14 :     tm->table_vacancy.vacancy_down = 0;
     965                 :         14 :     tm->table_vacancy.vacancy_up = 0;
     966                 :         14 :     tm->table_vacancy.vacancy = 0;
     967                 :            :     /* Only OpenFlow 1.1 and 1.2 can configure table-miss via table_mod.
     968                 :            :      * Only OpenFlow 1.4+ can configure eviction and vacancy events
     969                 :            :      * via table_mod.
     970                 :            :      */
     971         [ -  + ]:         14 :     if (!strcmp(setting, "controller")) {
     972                 :          0 :         tm->miss = OFPUTIL_TABLE_MISS_CONTROLLER;
     973                 :          0 :         *usable_versions = (1u << OFP11_VERSION) | (1u << OFP12_VERSION);
     974         [ +  + ]:         14 :     } else if (!strcmp(setting, "continue")) {
     975                 :          4 :         tm->miss = OFPUTIL_TABLE_MISS_CONTINUE;
     976                 :          4 :         *usable_versions = (1u << OFP11_VERSION) | (1u << OFP12_VERSION);
     977         [ +  + ]:         10 :     } else if (!strcmp(setting, "drop")) {
     978                 :          3 :         tm->miss = OFPUTIL_TABLE_MISS_DROP;
     979                 :          3 :         *usable_versions = (1u << OFP11_VERSION) | (1u << OFP12_VERSION);
     980         [ +  + ]:          7 :     } else if (!strcmp(setting, "evict")) {
     981                 :          2 :         tm->eviction = OFPUTIL_TABLE_EVICTION_ON;
     982                 :          2 :         *usable_versions = (1 << OFP14_VERSION) | (1u << OFP15_VERSION);
     983         [ +  + ]:          5 :     } else if (!strcmp(setting, "noevict")) {
     984                 :          1 :         tm->eviction = OFPUTIL_TABLE_EVICTION_OFF;
     985                 :          1 :         *usable_versions = (1 << OFP14_VERSION) | (1u << OFP15_VERSION);
     986         [ +  + ]:          4 :     } else if (!strncmp(setting, "vacancy", strcspn(setting, ":"))) {
     987                 :          3 :         tm->vacancy = OFPUTIL_TABLE_VACANCY_ON;
     988                 :          3 :         *usable_versions = (1 << OFP14_VERSION) | (1u << OFP15_VERSION);
     989                 :          3 :         char *error = parse_ofp_table_vacancy(tm, setting);
     990         [ -  + ]:          3 :         if (error) {
     991                 :          3 :             return error;
     992                 :            :         }
     993         [ +  - ]:          1 :     } else if (!strcmp(setting, "novacancy")) {
     994                 :          1 :         tm->vacancy = OFPUTIL_TABLE_VACANCY_OFF;
     995                 :          1 :         *usable_versions = (1 << OFP14_VERSION) | (1u << OFP15_VERSION);
     996                 :            :     } else {
     997                 :          0 :         return xasprintf("invalid table_mod setting %s", setting);
     998                 :            :     }
     999                 :            : 
    1000         [ -  + ]:         14 :     if (tm->table_id == 0xfe
    1001         [ #  # ]:          0 :         && tm->miss == OFPUTIL_TABLE_MISS_CONTINUE) {
    1002                 :          0 :         return xstrdup("last table's flow miss handling can not be continue");
    1003                 :            :     }
    1004                 :            : 
    1005                 :         14 :     return NULL;
    1006                 :            : }
    1007                 :            : 
    1008                 :            : 
    1009                 :            : /* Opens file 'file_name' and reads each line as a flow_mod of the specified
    1010                 :            :  * type (one of OFPFC_*).  Stores each flow_mod in '*fm', an array allocated
    1011                 :            :  * on the caller's behalf, and the number of flow_mods in '*n_fms'.
    1012                 :            :  *
    1013                 :            :  * If 'command' is given as -2, each line may start with a command name
    1014                 :            :  * ("add", "modify", "delete", "modify_strict", or "delete_strict").  A missing
    1015                 :            :  * command name is treated as "add".
    1016                 :            :  *
    1017                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
    1018                 :            :  * error.  The caller is responsible for freeing the returned string. */
    1019                 :            : char * OVS_WARN_UNUSED_RESULT
    1020                 :        308 : parse_ofp_flow_mod_file(const char *file_name, int command,
    1021                 :            :                         struct ofputil_flow_mod **fms, size_t *n_fms,
    1022                 :            :                         enum ofputil_protocol *usable_protocols)
    1023                 :            : {
    1024                 :            :     size_t allocated_fms;
    1025                 :            :     int line_number;
    1026                 :            :     FILE *stream;
    1027                 :            :     struct ds s;
    1028                 :            : 
    1029                 :        308 :     *usable_protocols = OFPUTIL_P_ANY;
    1030                 :            : 
    1031                 :        308 :     *fms = NULL;
    1032                 :        308 :     *n_fms = 0;
    1033                 :            : 
    1034         [ +  + ]:        308 :     stream = !strcmp(file_name, "-") ? stdin : fopen(file_name, "r");
    1035         [ -  + ]:        308 :     if (stream == NULL) {
    1036                 :          0 :         return xasprintf("%s: open failed (%s)",
    1037                 :          0 :                          file_name, ovs_strerror(errno));
    1038                 :            :     }
    1039                 :            : 
    1040                 :        308 :     allocated_fms = *n_fms;
    1041                 :        308 :     ds_init(&s);
    1042                 :        308 :     line_number = 0;
    1043         [ +  + ]:      11702 :     while (!ds_get_preprocessed_line(&s, stream, &line_number)) {
    1044                 :            :         char *error;
    1045                 :            :         enum ofputil_protocol usable;
    1046                 :            : 
    1047         [ +  + ]:      11395 :         if (*n_fms >= allocated_fms) {
    1048                 :       1009 :             *fms = x2nrealloc(*fms, &allocated_fms, sizeof **fms);
    1049                 :            :         }
    1050                 :      11395 :         error = parse_ofp_flow_mod_str(&(*fms)[*n_fms], ds_cstr(&s), command,
    1051                 :            :                                        &usable);
    1052         [ +  + ]:      11395 :         if (error) {
    1053                 :            :             char *err_msg;
    1054                 :            :             size_t i;
    1055                 :            : 
    1056         [ -  + ]:          1 :             for (i = 0; i < *n_fms; i++) {
    1057                 :          0 :                 free(CONST_CAST(struct ofpact *, (*fms)[i].ofpacts));
    1058                 :            :             }
    1059                 :          1 :             free(*fms);
    1060                 :          1 :             *fms = NULL;
    1061                 :          1 :             *n_fms = 0;
    1062                 :            : 
    1063                 :          1 :             ds_destroy(&s);
    1064         [ +  - ]:          1 :             if (stream != stdin) {
    1065                 :          1 :                 fclose(stream);
    1066                 :            :             }
    1067                 :            : 
    1068                 :          1 :             err_msg = xasprintf("%s:%d: %s", file_name, line_number, error);
    1069                 :          1 :             free(error);
    1070                 :          1 :             return err_msg;
    1071                 :            :         }
    1072                 :      11394 :         *usable_protocols &= usable; /* Each line can narrow the set. */
    1073                 :      11394 :         *n_fms += 1;
    1074                 :            :     }
    1075                 :            : 
    1076                 :        307 :     ds_destroy(&s);
    1077         [ +  + ]:        307 :     if (stream != stdin) {
    1078                 :        244 :         fclose(stream);
    1079                 :            :     }
    1080                 :        308 :     return NULL;
    1081                 :            : }
    1082                 :            : 
    1083                 :            : char * OVS_WARN_UNUSED_RESULT
    1084                 :        393 : parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *fsr,
    1085                 :            :                                  bool aggregate, const char *string,
    1086                 :            :                                  enum ofputil_protocol *usable_protocols)
    1087                 :            : {
    1088                 :            :     struct ofputil_flow_mod fm;
    1089                 :            :     char *error;
    1090                 :            : 
    1091                 :        393 :     error = parse_ofp_str(&fm, -1, string, usable_protocols);
    1092         [ -  + ]:        393 :     if (error) {
    1093                 :          0 :         return error;
    1094                 :            :     }
    1095                 :            : 
    1096                 :            :     /* Special table ID support not required for stats requests. */
    1097         [ +  + ]:        393 :     if (*usable_protocols & OFPUTIL_P_OF10_STD_TID) {
    1098                 :        377 :         *usable_protocols |= OFPUTIL_P_OF10_STD;
    1099                 :            :     }
    1100         [ +  + ]:        393 :     if (*usable_protocols & OFPUTIL_P_OF10_NXM_TID) {
    1101                 :        391 :         *usable_protocols |= OFPUTIL_P_OF10_NXM;
    1102                 :            :     }
    1103                 :            : 
    1104                 :        393 :     fsr->aggregate = aggregate;
    1105                 :        393 :     fsr->cookie = fm.cookie;
    1106                 :        393 :     fsr->cookie_mask = fm.cookie_mask;
    1107                 :        393 :     fsr->match = fm.match;
    1108                 :        393 :     fsr->out_port = fm.out_port;
    1109                 :        393 :     fsr->out_group = fm.out_group;
    1110                 :        393 :     fsr->table_id = fm.table_id;
    1111                 :        393 :     return NULL;
    1112                 :            : }
    1113                 :            : 
    1114                 :            : /* Parses a specification of a flow from 's' into 'flow'.  's' must take the
    1115                 :            :  * form FIELD=VALUE[,FIELD=VALUE]... where each FIELD is the name of a
    1116                 :            :  * mf_field.  Fields must be specified in a natural order for satisfying
    1117                 :            :  * prerequisites. If 'wc' is specified, masks the field in 'wc' for each of the
    1118                 :            :  * field specified in flow. If the map, 'names_portno' is specfied, converts
    1119                 :            :  * the in_port name into port no while setting the 'flow'.
    1120                 :            :  *
    1121                 :            :  * Returns NULL on success, otherwise a malloc()'d string that explains the
    1122                 :            :  * problem. */
    1123                 :            : char *
    1124                 :        579 : parse_ofp_exact_flow(struct flow *flow, struct flow_wildcards *wc,
    1125                 :            :                      const char *s, const struct simap *portno_names)
    1126                 :            : {
    1127                 :            :     char *pos, *key, *value_s;
    1128                 :        579 :     char *error = NULL;
    1129                 :            :     char *copy;
    1130                 :            : 
    1131                 :        579 :     memset(flow, 0, sizeof *flow);
    1132         [ +  + ]:        579 :     if (wc) {
    1133                 :         10 :         memset(wc, 0, sizeof *wc);
    1134                 :            :     }
    1135                 :            : 
    1136                 :        579 :     pos = copy = xstrdup(s);
    1137         [ +  + ]:       4272 :     while (ofputil_parse_key_value(&pos, &key, &value_s)) {
    1138                 :            :         const struct protocol *p;
    1139         [ +  + ]:       3693 :         if (parse_protocol(key, &p)) {
    1140         [ -  + ]:         12 :             if (flow->dl_type) {
    1141                 :          0 :                 error = xasprintf("%s: Ethernet type set multiple times", s);
    1142                 :          0 :                 goto exit;
    1143                 :            :             }
    1144                 :         12 :             flow->dl_type = htons(p->dl_type);
    1145         [ +  + ]:         12 :             if (wc) {
    1146                 :          7 :                 wc->masks.dl_type = OVS_BE16_MAX;
    1147                 :            :             }
    1148                 :            : 
    1149         [ +  + ]:         12 :             if (p->nw_proto) {
    1150         [ -  + ]:          7 :                 if (flow->nw_proto) {
    1151                 :          0 :                     error = xasprintf("%s: network protocol set "
    1152                 :            :                                       "multiple times", s);
    1153                 :          0 :                     goto exit;
    1154                 :            :                 }
    1155                 :          7 :                 flow->nw_proto = p->nw_proto;
    1156         [ +  + ]:          7 :                 if (wc) {
    1157                 :         12 :                     wc->masks.nw_proto = UINT8_MAX;
    1158                 :            :                 }
    1159                 :            :             }
    1160                 :            :         } else {
    1161                 :            :             const struct mf_field *mf;
    1162                 :            :             union mf_value value;
    1163                 :            :             char *field_error;
    1164                 :            : 
    1165                 :       3681 :             mf = mf_from_name(key);
    1166         [ -  + ]:       3681 :             if (!mf) {
    1167                 :          0 :                 error = xasprintf("%s: unknown field %s", s, key);
    1168                 :       3693 :                 goto exit;
    1169                 :            :             }
    1170                 :            : 
    1171         [ -  + ]:       3681 :             if (!mf_are_prereqs_ok(mf, flow, NULL)) {
    1172                 :          0 :                 error = xasprintf("%s: prerequisites not met for setting %s",
    1173                 :            :                                   s, key);
    1174                 :          0 :                 goto exit;
    1175                 :            :             }
    1176                 :            : 
    1177         [ -  + ]:       3681 :             if (mf_is_set(mf, flow)) {
    1178                 :          0 :                 error = xasprintf("%s: field %s set multiple times", s, key);
    1179                 :          0 :                 goto exit;
    1180                 :            :             }
    1181                 :            : 
    1182         [ +  + ]:       3681 :             if (!strcmp(key, "in_port")
    1183         [ -  + ]:        563 :                 && portno_names
    1184         [ #  # ]:          0 :                 && simap_contains(portno_names, value_s)) {
    1185                 :          0 :                 flow->in_port.ofp_port = u16_to_ofp(
    1186                 :          0 :                     simap_get(portno_names, value_s));
    1187         [ #  # ]:          0 :                 if (wc) {
    1188                 :            :                     wc->masks.in_port.ofp_port
    1189                 :          0 :                         = u16_to_ofp(ntohs(OVS_BE16_MAX));
    1190                 :            :                 }
    1191                 :            :             } else {
    1192                 :       3681 :                 field_error = mf_parse_value(mf, value_s, &value);
    1193         [ -  + ]:       3681 :                 if (field_error) {
    1194                 :          0 :                     error = xasprintf("%s: bad value for %s (%s)",
    1195                 :            :                                       s, key, field_error);
    1196                 :          0 :                     free(field_error);
    1197                 :          0 :                     goto exit;
    1198                 :            :                 }
    1199                 :            : 
    1200                 :       3681 :                 mf_set_flow_value(mf, &value, flow);
    1201         [ +  + ]:       3681 :                 if (wc) {
    1202                 :       3681 :                     mf_mask_field(mf, wc);
    1203                 :            :                 }
    1204                 :            :             }
    1205                 :            :         }
    1206                 :            :     }
    1207                 :            : 
    1208         [ +  + ]:        579 :     if (!flow->in_port.ofp_port) {
    1209                 :         16 :         flow->in_port.ofp_port = OFPP_NONE;
    1210                 :            :     }
    1211                 :            : 
    1212                 :            : exit:
    1213                 :        579 :     free(copy);
    1214                 :            : 
    1215         [ -  + ]:        579 :     if (error) {
    1216                 :          0 :         memset(flow, 0, sizeof *flow);
    1217         [ #  # ]:          0 :         if (wc) {
    1218                 :          0 :             memset(wc, 0, sizeof *wc);
    1219                 :            :         }
    1220                 :            :     }
    1221                 :        579 :     return error;
    1222                 :            : }
    1223                 :            : 
    1224                 :            : static char * OVS_WARN_UNUSED_RESULT
    1225                 :        176 : parse_bucket_str(struct ofputil_bucket *bucket, char *str_, uint8_t group_type,
    1226                 :            :                   enum ofputil_protocol *usable_protocols)
    1227                 :            : {
    1228                 :            :     char *pos, *key, *value;
    1229                 :            :     struct ofpbuf ofpacts;
    1230                 :            :     struct ds actions;
    1231                 :            :     char *error;
    1232                 :            : 
    1233                 :        176 :     bucket->weight = group_type == OFPGT11_SELECT ? 1 : 0;
    1234                 :        176 :     bucket->bucket_id = OFPG15_BUCKET_ALL;
    1235                 :        176 :     bucket->watch_port = OFPP_ANY;
    1236                 :        176 :     bucket->watch_group = OFPG_ANY;
    1237                 :            : 
    1238                 :        176 :     ds_init(&actions);
    1239                 :            : 
    1240                 :        176 :     pos = str_;
    1241                 :        176 :     error = NULL;
    1242         [ +  + ]:        459 :     while (ofputil_parse_key_value(&pos, &key, &value)) {
    1243         [ +  + ]:        283 :         if (!strcasecmp(key, "weight")) {
    1244                 :         32 :             error = str_to_u16(value, "weight", &bucket->weight);
    1245         [ +  + ]:        251 :         } else if (!strcasecmp(key, "watch_port")) {
    1246         [ +  - ]:          3 :             if (!ofputil_port_from_string(value, &bucket->watch_port)
    1247         [ -  + ]:          3 :                 || (ofp_to_u16(bucket->watch_port) >= ofp_to_u16(OFPP_MAX)
    1248         [ #  # ]:          0 :                     && bucket->watch_port != OFPP_ANY)) {
    1249                 :          3 :                 error = xasprintf("%s: invalid watch_port", value);
    1250                 :            :             }
    1251         [ -  + ]:        248 :         } else if (!strcasecmp(key, "watch_group")) {
    1252                 :          0 :             error = str_to_u32(value, &bucket->watch_group);
    1253 [ #  # ][ #  # ]:          0 :             if (!error && bucket->watch_group > OFPG_MAX) {
    1254                 :          0 :                 error = xasprintf("invalid watch_group id %"PRIu32,
    1255                 :            :                                   bucket->watch_group);
    1256                 :            :             }
    1257         [ +  + ]:        248 :         } else if (!strcasecmp(key, "bucket_id")) {
    1258                 :         66 :             error = str_to_u32(value, &bucket->bucket_id);
    1259 [ +  - ][ -  + ]:         66 :             if (!error && bucket->bucket_id > OFPG15_BUCKET_MAX) {
    1260                 :          0 :                 error = xasprintf("invalid bucket_id id %"PRIu32,
    1261                 :            :                                   bucket->bucket_id);
    1262                 :            :             }
    1263                 :         66 :             *usable_protocols &= OFPUTIL_P_OF15_UP;
    1264 [ +  - ][ +  + ]:        182 :         } else if (!strcasecmp(key, "action") || !strcasecmp(key, "actions")) {
    1265                 :         80 :             ds_put_format(&actions, "%s,", value);
    1266                 :            :         } else {
    1267                 :        102 :             ds_put_format(&actions, "%s(%s),", key, value);
    1268                 :            :         }
    1269                 :            : 
    1270         [ -  + ]:        283 :         if (error) {
    1271                 :          0 :             ds_destroy(&actions);
    1272                 :          0 :             return error;
    1273                 :            :         }
    1274                 :            :     }
    1275                 :            : 
    1276         [ -  + ]:        176 :     if (!actions.length) {
    1277                 :          0 :         return xstrdup("bucket must specify actions");
    1278                 :            :     }
    1279                 :        176 :     ds_chomp(&actions, ',');
    1280                 :            : 
    1281                 :        176 :     ofpbuf_init(&ofpacts, 0);
    1282                 :        176 :     error = ofpacts_parse_actions(ds_cstr(&actions), &ofpacts,
    1283                 :            :                                   usable_protocols);
    1284                 :        176 :     ds_destroy(&actions);
    1285         [ -  + ]:        176 :     if (error) {
    1286                 :          0 :         ofpbuf_uninit(&ofpacts);
    1287                 :          0 :         return error;
    1288                 :            :     }
    1289                 :        176 :     bucket->ofpacts = ofpacts.data;
    1290                 :        176 :     bucket->ofpacts_len = ofpacts.size;
    1291                 :            : 
    1292                 :        176 :     return NULL;
    1293                 :            : }
    1294                 :            : 
    1295                 :            : static char * OVS_WARN_UNUSED_RESULT
    1296                 :          3 : parse_select_group_field(char *s, struct field_array *fa,
    1297                 :            :                          enum ofputil_protocol *usable_protocols)
    1298                 :            : {
    1299                 :            :     char *name, *value_str;
    1300                 :            : 
    1301         [ +  + ]:         12 :     while (ofputil_parse_key_value(&s, &name, &value_str)) {
    1302                 :          9 :         const struct mf_field *mf = mf_from_name(name);
    1303                 :            : 
    1304         [ +  - ]:          9 :         if (mf) {
    1305                 :            :             char *error;
    1306                 :            :             union mf_value value;
    1307                 :            : 
    1308         [ -  + ]:          9 :             if (bitmap_is_set(fa->used.bm, mf->id)) {
    1309                 :          0 :                 return xasprintf("%s: duplicate field", name);
    1310                 :            :             }
    1311                 :            : 
    1312         [ -  + ]:          9 :             if (*value_str) {
    1313                 :          0 :                 error = mf_parse_value(mf, value_str, &value);
    1314         [ #  # ]:          0 :                 if (error) {
    1315                 :          0 :                     return error;
    1316                 :            :                 }
    1317                 :            : 
    1318                 :            :                 /* The mask cannot be all-zeros */
    1319   [ #  #  #  # ]:          0 :                 if (!mf_is_tun_metadata(mf) &&
    1320                 :          0 :                     is_all_zeros(&value, mf->n_bytes)) {
    1321                 :          0 :                     return xasprintf("%s: values are wildcards here "
    1322                 :            :                                      "and must not be all-zeros", s);
    1323                 :            :                 }
    1324                 :            : 
    1325                 :            :                 /* The values parsed are masks for fields used
    1326                 :            :                  * by the selection method */
    1327         [ #  # ]:          0 :                 if (!mf_is_mask_valid(mf, &value)) {
    1328                 :          0 :                     return xasprintf("%s: invalid mask for field %s",
    1329                 :            :                                      value_str, mf->name);
    1330                 :            :                 }
    1331                 :            :             } else {
    1332                 :          9 :                 memset(&value, 0xff, mf->n_bytes);
    1333                 :            :             }
    1334                 :            : 
    1335                 :          9 :             field_array_set(mf->id, &value, fa);
    1336                 :            : 
    1337         [ +  - ]:          9 :             if (is_all_ones(&value, mf->n_bytes)) {
    1338                 :          9 :                 *usable_protocols &= mf->usable_protocols_exact;
    1339         [ #  # ]:          0 :             } else if (mf->usable_protocols_bitwise == mf->usable_protocols_cidr
    1340         [ #  # ]:          0 :                        || ip_is_cidr(value.be32)) {
    1341                 :          0 :                 *usable_protocols &= mf->usable_protocols_cidr;
    1342                 :            :             } else {
    1343                 :          9 :                 *usable_protocols &= mf->usable_protocols_bitwise;
    1344                 :            :             }
    1345                 :            :         } else {
    1346                 :          0 :             return xasprintf("%s: unknown field %s", s, name);
    1347                 :            :         }
    1348                 :            :     }
    1349                 :            : 
    1350                 :          3 :     return NULL;
    1351                 :            : }
    1352                 :            : 
    1353                 :            : static char * OVS_WARN_UNUSED_RESULT
    1354                 :        179 : parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, int command,
    1355                 :            :                           char *string,
    1356                 :            :                           enum ofputil_protocol *usable_protocols)
    1357                 :            : {
    1358                 :            :     enum {
    1359                 :            :         F_GROUP_TYPE            = 1 << 0,
    1360                 :            :         F_BUCKETS               = 1 << 1,
    1361                 :            :         F_COMMAND_BUCKET_ID     = 1 << 2,
    1362                 :            :         F_COMMAND_BUCKET_ID_ALL = 1 << 3,
    1363                 :            :     } fields;
    1364                 :        179 :     bool had_type = false;
    1365                 :        179 :     bool had_command_bucket_id = false;
    1366                 :            :     struct ofputil_bucket *bucket;
    1367                 :        179 :     char *error = NULL;
    1368                 :            : 
    1369                 :        179 :     *usable_protocols = OFPUTIL_P_OF11_UP;
    1370                 :            : 
    1371         [ +  + ]:        179 :     if (command == -2) {
    1372                 :            :         size_t len;
    1373                 :            : 
    1374                 :         39 :         string += strspn(string, " \t\r\n");   /* Skip white space. */
    1375                 :         39 :         len = strcspn(string, ", \t\r\n"); /* Get length of the first token. */
    1376                 :            : 
    1377         [ +  + ]:         39 :         if (!strncmp(string, "add", len)) {
    1378                 :          2 :             command = OFPGC11_ADD;
    1379         [ +  + ]:         37 :         } else if (!strncmp(string, "delete", len)) {
    1380                 :          1 :             command = OFPGC11_DELETE;
    1381         [ -  + ]:         36 :         } else if (!strncmp(string, "modify", len)) {
    1382                 :          0 :             command = OFPGC11_MODIFY;
    1383         [ -  + ]:         36 :         } else if (!strncmp(string, "add_or_mod", len)) {
    1384                 :          0 :             command = OFPGC11_ADD_OR_MOD;
    1385         [ +  + ]:         36 :         } else if (!strncmp(string, "insert_bucket", len)) {
    1386                 :          1 :             command = OFPGC15_INSERT_BUCKET;
    1387         [ -  + ]:         35 :         } else if (!strncmp(string, "remove_bucket", len)) {
    1388                 :          0 :             command = OFPGC15_REMOVE_BUCKET;
    1389                 :            :         } else {
    1390                 :         35 :             len = 0;
    1391                 :         35 :             command = OFPGC11_ADD;
    1392                 :            :         }
    1393                 :         39 :         string += len;
    1394                 :            :     }
    1395                 :            : 
    1396   [ +  +  +  +  :        179 :     switch (command) {
                +  +  - ]
    1397                 :            :     case OFPGC11_ADD:
    1398                 :         89 :         fields = F_GROUP_TYPE | F_BUCKETS;
    1399                 :         89 :         break;
    1400                 :            : 
    1401                 :            :     case OFPGC11_DELETE:
    1402                 :         45 :         fields = 0;
    1403                 :         45 :         break;
    1404                 :            : 
    1405                 :            :     case OFPGC11_MODIFY:
    1406                 :          3 :         fields = F_GROUP_TYPE | F_BUCKETS;
    1407                 :          3 :         break;
    1408                 :            : 
    1409                 :            :     case OFPGC11_ADD_OR_MOD:
    1410                 :          4 :         fields = F_GROUP_TYPE | F_BUCKETS;
    1411                 :          4 :         break;
    1412                 :            : 
    1413                 :            :     case OFPGC15_INSERT_BUCKET:
    1414                 :         20 :         fields = F_BUCKETS | F_COMMAND_BUCKET_ID;
    1415                 :         20 :         *usable_protocols &= OFPUTIL_P_OF15_UP;
    1416                 :         20 :         break;
    1417                 :            : 
    1418                 :            :     case OFPGC15_REMOVE_BUCKET:
    1419                 :         18 :         fields = F_COMMAND_BUCKET_ID | F_COMMAND_BUCKET_ID_ALL;
    1420                 :         18 :         *usable_protocols &= OFPUTIL_P_OF15_UP;
    1421                 :         18 :         break;
    1422                 :            : 
    1423                 :            :     default:
    1424                 :          0 :         OVS_NOT_REACHED();
    1425                 :            :     }
    1426                 :            : 
    1427                 :        179 :     memset(gm, 0, sizeof *gm);
    1428                 :        179 :     gm->command = command;
    1429                 :        179 :     gm->group_id = OFPG_ANY;
    1430                 :        179 :     gm->command_bucket_id = OFPG15_BUCKET_ALL;
    1431                 :        179 :     ovs_list_init(&gm->buckets);
    1432 [ +  + ][ +  + ]:        179 :     if (command == OFPGC11_DELETE && string[0] == '\0') {
    1433                 :         14 :         gm->group_id = OFPG_ALL;
    1434                 :         14 :         return NULL;
    1435                 :            :     }
    1436                 :            : 
    1437                 :        165 :     *usable_protocols = OFPUTIL_P_OF11_UP;
    1438                 :            : 
    1439                 :            :     /* Strip the buckets off the end of 'string', if there are any, saving a
    1440                 :            :      * pointer for later.  We want to parse the buckets last because the bucket
    1441                 :            :      * type influences bucket defaults. */
    1442                 :        165 :     char *bkt_str = strstr(string, "bucket=");
    1443         [ +  + ]:        165 :     if (bkt_str) {
    1444         [ -  + ]:        108 :         if (!(fields & F_BUCKETS)) {
    1445                 :          0 :             error = xstrdup("bucket is not needed");
    1446                 :          0 :             goto out;
    1447                 :            :         }
    1448                 :        108 :         *bkt_str = '\0';
    1449                 :            :     }
    1450                 :            : 
    1451                 :            :     /* Parse everything before the buckets. */
    1452                 :        165 :     char *pos = string;
    1453                 :            :     char *name, *value;
    1454         [ +  + ]:        466 :     while (ofputil_parse_key_value(&pos, &name, &value)) {
    1455         [ +  + ]:        305 :         if (!strcmp(name, "command_bucket_id")) {
    1456         [ -  + ]:         36 :             if (!(fields & F_COMMAND_BUCKET_ID)) {
    1457                 :          0 :                 error = xstrdup("command bucket id is not needed");
    1458                 :          0 :                 goto out;
    1459                 :            :             }
    1460         [ +  + ]:         36 :             if (!strcmp(value, "all")) {
    1461                 :          2 :                 gm->command_bucket_id = OFPG15_BUCKET_ALL;
    1462         [ +  + ]:         34 :             } else if (!strcmp(value, "first")) {
    1463                 :         10 :                 gm->command_bucket_id = OFPG15_BUCKET_FIRST;
    1464         [ +  + ]:         24 :             } else if (!strcmp(value, "last")) {
    1465                 :         12 :                 gm->command_bucket_id = OFPG15_BUCKET_LAST;
    1466                 :            :             } else {
    1467                 :         12 :                 error = str_to_u32(value, &gm->command_bucket_id);
    1468         [ -  + ]:         12 :                 if (error) {
    1469                 :          0 :                     goto out;
    1470                 :            :                 }
    1471         [ +  + ]:         12 :                 if (gm->command_bucket_id > OFPG15_BUCKET_MAX
    1472         [ +  - ]:          2 :                     && (gm->command_bucket_id != OFPG15_BUCKET_FIRST
    1473         [ +  - ]:          2 :                         && gm->command_bucket_id != OFPG15_BUCKET_LAST
    1474         [ +  - ]:          2 :                         && gm->command_bucket_id != OFPG15_BUCKET_ALL)) {
    1475                 :          2 :                     error = xasprintf("invalid command bucket id %"PRIu32,
    1476                 :            :                                       gm->command_bucket_id);
    1477                 :          2 :                     goto out;
    1478                 :            :                 }
    1479                 :            :             }
    1480         [ +  + ]:         34 :             if (gm->command_bucket_id == OFPG15_BUCKET_ALL
    1481         [ -  + ]:          2 :                 && !(fields & F_COMMAND_BUCKET_ID_ALL)) {
    1482                 :          0 :                 error = xstrdup("command_bucket_id=all is not permitted");
    1483                 :          0 :                 goto out;
    1484                 :            :             }
    1485                 :         34 :             had_command_bucket_id = true;
    1486         [ +  + ]:        269 :         } else if (!strcmp(name, "group_id")) {
    1487         [ -  + ]:        165 :             if(!strcmp(value, "all")) {
    1488                 :          0 :                 gm->group_id = OFPG_ALL;
    1489                 :            :             } else {
    1490                 :        165 :                 error = str_to_u32(value, &gm->group_id);
    1491         [ -  + ]:        165 :                 if (error) {
    1492                 :          0 :                     goto out;
    1493                 :            :                 }
    1494 [ +  - ][ +  + ]:        165 :                 if (gm->group_id != OFPG_ALL && gm->group_id > OFPG_MAX) {
    1495                 :          2 :                     error = xasprintf("invalid group id %"PRIu32,
    1496                 :            :                                       gm->group_id);
    1497                 :          2 :                     goto out;
    1498                 :            :                 }
    1499                 :            :             }
    1500         [ +  + ]:        104 :         } else if (!strcmp(name, "type")){
    1501         [ -  + ]:         96 :             if (!(fields & F_GROUP_TYPE)) {
    1502                 :          0 :                 error = xstrdup("type is not needed");
    1503                 :          0 :                 goto out;
    1504                 :            :             }
    1505         [ +  + ]:         96 :             if (!strcmp(value, "all")) {
    1506                 :         60 :                 gm->type = OFPGT11_ALL;
    1507         [ +  + ]:         36 :             } else if (!strcmp(value, "select")) {
    1508                 :         21 :                 gm->type = OFPGT11_SELECT;
    1509         [ +  + ]:         15 :             } else if (!strcmp(value, "indirect")) {
    1510                 :         14 :                 gm->type = OFPGT11_INDIRECT;
    1511 [ -  + ][ #  # ]:          1 :             } else if (!strcmp(value, "ff") ||
    1512                 :          0 :                        !strcmp(value, "fast_failover")) {
    1513                 :          1 :                 gm->type = OFPGT11_FF;
    1514                 :            :             } else {
    1515                 :          0 :                 error = xasprintf("invalid group type %s", value);
    1516                 :          0 :                 goto out;
    1517                 :            :             }
    1518                 :         96 :             had_type = true;
    1519         [ +  + ]:          8 :         } else if (!strcmp(name, "selection_method")) {
    1520         [ -  + ]:          5 :             if (!(fields & F_GROUP_TYPE)) {
    1521                 :          0 :                 error = xstrdup("selection method is not needed");
    1522                 :          0 :                 goto out;
    1523                 :            :             }
    1524         [ -  + ]:          5 :             if (strlen(value) >= NTR_MAX_SELECTION_METHOD_LEN) {
    1525                 :          0 :                 error = xasprintf("selection method is longer than %u"
    1526                 :            :                                   " bytes long",
    1527                 :            :                                   NTR_MAX_SELECTION_METHOD_LEN - 1);
    1528                 :          0 :                 goto out;
    1529                 :            :             }
    1530                 :          5 :             memset(gm->props.selection_method, '\0',
    1531                 :            :                    NTR_MAX_SELECTION_METHOD_LEN);
    1532                 :          5 :             strcpy(gm->props.selection_method, value);
    1533                 :          5 :             *usable_protocols &= OFPUTIL_P_OF15_UP;
    1534         [ -  + ]:          3 :         } else if (!strcmp(name, "selection_method_param")) {
    1535         [ #  # ]:          0 :             if (!(fields & F_GROUP_TYPE)) {
    1536                 :          0 :                 error = xstrdup("selection method param is not needed");
    1537                 :          0 :                 goto out;
    1538                 :            :             }
    1539                 :          0 :             error = str_to_u64(value, &gm->props.selection_method_param);
    1540         [ #  # ]:          0 :             if (error) {
    1541                 :          0 :                 goto out;
    1542                 :            :             }
    1543                 :          0 :             *usable_protocols &= OFPUTIL_P_OF15_UP;
    1544         [ +  - ]:          3 :         } else if (!strcmp(name, "fields")) {
    1545         [ -  + ]:          3 :             if (!(fields & F_GROUP_TYPE)) {
    1546                 :          0 :                 error = xstrdup("fields are not needed");
    1547                 :          0 :                 goto out;
    1548                 :            :             }
    1549                 :          3 :             error = parse_select_group_field(value, &gm->props.fields,
    1550                 :            :                                              usable_protocols);
    1551         [ -  + ]:          3 :             if (error) {
    1552                 :          0 :                 goto out;
    1553                 :            :             }
    1554                 :          3 :             *usable_protocols &= OFPUTIL_P_OF15_UP;
    1555                 :            :         } else {
    1556                 :          0 :             error = xasprintf("unknown keyword %s", name);
    1557                 :          0 :             goto out;
    1558                 :            :         }
    1559                 :            :     }
    1560         [ -  + ]:        161 :     if (gm->group_id == OFPG_ANY) {
    1561                 :          0 :         error = xstrdup("must specify a group_id");
    1562                 :          0 :         goto out;
    1563                 :            :     }
    1564 [ +  + ][ -  + ]:        161 :     if (fields & F_GROUP_TYPE && !had_type) {
    1565                 :          0 :         error = xstrdup("must specify a type");
    1566                 :          0 :         goto out;
    1567                 :            :     }
    1568                 :            : 
    1569         [ +  + ]:        161 :     if (fields & F_COMMAND_BUCKET_ID) {
    1570 [ +  + ][ -  + ]:         36 :         if (!(fields & F_COMMAND_BUCKET_ID_ALL || had_command_bucket_id)) {
    1571                 :          0 :             error = xstrdup("must specify a command bucket id");
    1572                 :          0 :             goto out;
    1573                 :            :         }
    1574         [ -  + ]:        125 :     } else if (had_command_bucket_id) {
    1575                 :          0 :         error = xstrdup("command bucket id is not needed");
    1576                 :          0 :         goto out;
    1577                 :            :     }
    1578                 :            : 
    1579                 :            :     /* Now parse the buckets, if any. */
    1580         [ +  + ]:        337 :     while (bkt_str) {
    1581                 :            :         char *next_bkt_str;
    1582                 :            : 
    1583                 :        176 :         bkt_str = strchr(bkt_str + 1, '=');
    1584         [ -  + ]:        176 :         if (!bkt_str) {
    1585                 :          0 :             error = xstrdup("must specify bucket content");
    1586                 :          0 :             goto out;
    1587                 :            :         }
    1588                 :        176 :         bkt_str++;
    1589                 :            : 
    1590                 :        176 :         next_bkt_str = strstr(bkt_str, "bucket=");
    1591         [ +  + ]:        176 :         if (next_bkt_str) {
    1592                 :         70 :             *next_bkt_str = '\0';
    1593                 :            :         }
    1594                 :            : 
    1595                 :        176 :         bucket = xzalloc(sizeof(struct ofputil_bucket));
    1596                 :        176 :         error = parse_bucket_str(bucket, bkt_str, gm->type, usable_protocols);
    1597         [ -  + ]:        176 :         if (error) {
    1598                 :          0 :             free(bucket);
    1599                 :          0 :             goto out;
    1600                 :            :         }
    1601                 :        176 :         ovs_list_push_back(&gm->buckets, &bucket->list_node);
    1602                 :            : 
    1603 [ +  + ][ -  + ]:        176 :         if (gm->type != OFPGT11_SELECT && bucket->weight) {
    1604                 :          0 :             error = xstrdup("Only select groups can have bucket weights.");
    1605                 :          0 :             goto out;
    1606                 :            :         }
    1607                 :            : 
    1608                 :        176 :         bkt_str = next_bkt_str;
    1609                 :            :     }
    1610 [ +  + ][ +  + ]:        161 :     if (gm->type == OFPGT11_INDIRECT && !ovs_list_is_short(&gm->buckets)) {
    1611                 :          2 :         error = xstrdup("Indirect groups can have at most one bucket.");
    1612                 :          2 :         goto out;
    1613                 :            :     }
    1614                 :            : 
    1615                 :        159 :     return NULL;
    1616                 :            :  out:
    1617                 :          6 :     ofputil_uninit_group_mod(gm);
    1618                 :        179 :     return error;
    1619                 :            : }
    1620                 :            : 
    1621                 :            : /* If 'command' is given as -2, each line may start with a command name ("add",
    1622                 :            :  * "modify", "add_or_mod", "delete", "insert_bucket", or "remove_bucket").  A
    1623                 :            :  * missing command name is treated as "add".
    1624                 :            :  */
    1625                 :            : char * OVS_WARN_UNUSED_RESULT
    1626                 :        179 : parse_ofp_group_mod_str(struct ofputil_group_mod *gm, int command,
    1627                 :            :                         const char *str_,
    1628                 :            :                         enum ofputil_protocol *usable_protocols)
    1629                 :            : {
    1630                 :        179 :     char *string = xstrdup(str_);
    1631                 :        179 :     char *error = parse_ofp_group_mod_str__(gm, command, string,
    1632                 :            :                                             usable_protocols);
    1633                 :        179 :     free(string);
    1634                 :            : 
    1635         [ +  + ]:        179 :     if (error) {
    1636                 :          6 :         ofputil_uninit_group_mod(gm);
    1637                 :            :     }
    1638                 :        179 :     return error;
    1639                 :            : }
    1640                 :            : 
    1641                 :            : /* If 'command' is given as -2, each line may start with a command name ("add",
    1642                 :            :  * "modify", "add_or_mod", "delete", "insert_bucket", or "remove_bucket").  A
    1643                 :            :  * missing command name is treated as "add".
    1644                 :            :  */
    1645                 :            : char * OVS_WARN_UNUSED_RESULT
    1646                 :         21 : parse_ofp_group_mod_file(const char *file_name, int command,
    1647                 :            :                          struct ofputil_group_mod **gms, size_t *n_gms,
    1648                 :            :                          enum ofputil_protocol *usable_protocols)
    1649                 :            : {
    1650                 :            :     size_t allocated_gms;
    1651                 :            :     int line_number;
    1652                 :            :     FILE *stream;
    1653                 :            :     struct ds s;
    1654                 :            : 
    1655                 :         21 :     *gms = NULL;
    1656                 :         21 :     *n_gms = 0;
    1657                 :            : 
    1658         [ +  + ]:         21 :     stream = !strcmp(file_name, "-") ? stdin : fopen(file_name, "r");
    1659         [ -  + ]:         21 :     if (stream == NULL) {
    1660                 :          0 :         return xasprintf("%s: open failed (%s)",
    1661                 :          0 :                          file_name, ovs_strerror(errno));
    1662                 :            :     }
    1663                 :            : 
    1664                 :         21 :     allocated_gms = *n_gms;
    1665                 :         21 :     ds_init(&s);
    1666                 :         21 :     line_number = 0;
    1667                 :         21 :     *usable_protocols = OFPUTIL_P_OF11_UP;
    1668         [ +  + ]:         60 :     while (!ds_get_preprocessed_line(&s, stream, &line_number)) {
    1669                 :            :         enum ofputil_protocol usable;
    1670                 :            :         char *error;
    1671                 :            : 
    1672         [ +  - ]:         39 :         if (*n_gms >= allocated_gms) {
    1673                 :            :             struct ofputil_group_mod *new_gms;
    1674                 :            :             size_t i;
    1675                 :            : 
    1676                 :         39 :             new_gms = x2nrealloc(*gms, &allocated_gms, sizeof **gms);
    1677         [ +  + ]:         62 :             for (i = 0; i < *n_gms; i++) {
    1678                 :         23 :                 ovs_list_moved(&new_gms[i].buckets, &(*gms)[i].buckets);
    1679                 :            :             }
    1680                 :         39 :             *gms = new_gms;
    1681                 :            :         }
    1682                 :         39 :         error = parse_ofp_group_mod_str(&(*gms)[*n_gms], command, ds_cstr(&s),
    1683                 :            :                                         &usable);
    1684         [ -  + ]:         39 :         if (error) {
    1685                 :            :             size_t i;
    1686                 :            : 
    1687         [ #  # ]:          0 :             for (i = 0; i < *n_gms; i++) {
    1688                 :          0 :                 ofputil_uninit_group_mod(&(*gms)[i]);
    1689                 :            :             }
    1690                 :          0 :             free(*gms);
    1691                 :          0 :             *gms = NULL;
    1692                 :          0 :             *n_gms = 0;
    1693                 :            : 
    1694                 :          0 :             ds_destroy(&s);
    1695         [ #  # ]:          0 :             if (stream != stdin) {
    1696                 :          0 :                 fclose(stream);
    1697                 :            :             }
    1698                 :            : 
    1699                 :          0 :             return xasprintf("%s:%d: %s", file_name, line_number, error);
    1700                 :            :         }
    1701                 :         39 :         *usable_protocols &= usable;
    1702                 :         39 :         *n_gms += 1;
    1703                 :            :     }
    1704                 :            : 
    1705                 :         21 :     ds_destroy(&s);
    1706         [ +  + ]:         21 :     if (stream != stdin) {
    1707                 :         17 :         fclose(stream);
    1708                 :            :     }
    1709                 :         21 :     return NULL;
    1710                 :            : }
    1711                 :            : 
    1712                 :            : static void
    1713                 :          0 : free_bundle_msgs(struct ofputil_bundle_msg **bms, size_t *n_bms)
    1714                 :            : {
    1715         [ #  # ]:          0 :     for (size_t i = 0; i < *n_bms; i++) {
    1716      [ #  #  # ]:          0 :         switch ((int)(*bms)[i].type) {
    1717                 :            :         case OFPTYPE_FLOW_MOD:
    1718                 :          0 :             free(CONST_CAST(struct ofpact *, (*bms)[i].fm.ofpacts));
    1719                 :          0 :             break;
    1720                 :            :         case OFPTYPE_GROUP_MOD:
    1721                 :          0 :             ofputil_uninit_group_mod(&(*bms)[i].gm);
    1722                 :          0 :             break;
    1723                 :            :         default:
    1724                 :          0 :             break;
    1725                 :            :         }
    1726                 :            :     }
    1727                 :          0 :     free(*bms);
    1728                 :          0 :     *bms = NULL;
    1729                 :          0 :     *n_bms = 0;
    1730                 :          0 : }
    1731                 :            : 
    1732                 :            : /* Opens file 'file_name' and reads each line as a flow_mod or a group_mod,
    1733                 :            :  * depending on the first keyword on each line.  Stores each flow and group
    1734                 :            :  * mods in '*bms', an array allocated on the caller's behalf, and the number of
    1735                 :            :  * messages in '*n_bms'.
    1736                 :            :  *
    1737                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
    1738                 :            :  * error.  The caller is responsible for freeing the returned string. */
    1739                 :            : char * OVS_WARN_UNUSED_RESULT
    1740                 :          2 : parse_ofp_bundle_file(const char *file_name,
    1741                 :            :                       struct ofputil_bundle_msg **bms, size_t *n_bms,
    1742                 :            :                       enum ofputil_protocol *usable_protocols)
    1743                 :            : {
    1744                 :            :     size_t allocated_bms;
    1745                 :          2 :     char *error = NULL;
    1746                 :            :     int line_number;
    1747                 :            :     FILE *stream;
    1748                 :            :     struct ds ds;
    1749                 :            : 
    1750                 :          2 :     *usable_protocols = OFPUTIL_P_ANY;
    1751                 :            : 
    1752                 :          2 :     *bms = NULL;
    1753                 :          2 :     *n_bms = 0;
    1754                 :            : 
    1755         [ +  - ]:          2 :     stream = !strcmp(file_name, "-") ? stdin : fopen(file_name, "r");
    1756         [ -  + ]:          2 :     if (stream == NULL) {
    1757                 :          0 :         return xasprintf("%s: open failed (%s)",
    1758                 :          0 :                          file_name, ovs_strerror(errno));
    1759                 :            :     }
    1760                 :            : 
    1761                 :          2 :     allocated_bms = *n_bms;
    1762                 :          2 :     ds_init(&ds);
    1763                 :          2 :     line_number = 0;
    1764         [ +  + ]:         14 :     while (!ds_get_preprocessed_line(&ds, stream, &line_number)) {
    1765                 :            :         enum ofputil_protocol usable;
    1766                 :         12 :         char *s = ds_cstr(&ds);
    1767                 :            :         size_t len;
    1768                 :            : 
    1769         [ +  + ]:         12 :         if (*n_bms >= allocated_bms) {
    1770                 :            :             struct ofputil_bundle_msg *new_bms;
    1771                 :            : 
    1772                 :          8 :             new_bms = x2nrealloc(*bms, &allocated_bms, sizeof **bms);
    1773         [ +  + ]:         26 :             for (size_t i = 0; i < *n_bms; i++) {
    1774         [ +  + ]:         18 :                 if (new_bms[i].type == OFPTYPE_GROUP_MOD) {
    1775                 :         11 :                     ovs_list_moved(&new_bms[i].gm.buckets,
    1776                 :         11 :                                    &(*bms)[i].gm.buckets);
    1777                 :            :                 }
    1778                 :            :             }
    1779                 :          8 :             *bms = new_bms;
    1780                 :            :         }
    1781                 :            : 
    1782                 :         12 :         s += strspn(s, " \t\r\n");   /* Skip white space. */
    1783                 :         12 :         len = strcspn(s, ", \t\r\n"); /* Get length of the first token. */
    1784                 :            : 
    1785         [ +  + ]:         12 :         if (!strncmp(s, "flow", len)) {
    1786                 :          8 :             s += len;
    1787                 :          8 :             error = parse_ofp_flow_mod_str(&(*bms)[*n_bms].fm, s, -2, &usable);
    1788         [ -  + ]:          8 :             if (error) {
    1789                 :          0 :                 break;
    1790                 :            :             }
    1791                 :          8 :             (*bms)[*n_bms].type = OFPTYPE_FLOW_MOD;
    1792         [ +  - ]:          4 :         } else if (!strncmp(s, "group", len)) {
    1793                 :          4 :             s += len;
    1794                 :          4 :             error = parse_ofp_group_mod_str(&(*bms)[*n_bms].gm, -2, s,
    1795                 :            :                                             &usable);
    1796         [ -  + ]:          4 :             if (error) {
    1797                 :          0 :                 break;
    1798                 :            :             }
    1799                 :          4 :             (*bms)[*n_bms].type = OFPTYPE_GROUP_MOD;
    1800                 :            :         } else {
    1801                 :          0 :             error = xasprintf("Unsupported bundle message type: %.*s",
    1802                 :            :                               (int)len, s);
    1803                 :          0 :             break;
    1804                 :            :         }
    1805                 :            : 
    1806                 :         12 :         *usable_protocols &= usable; /* Each line can narrow the set. */
    1807                 :         12 :         *n_bms += 1;
    1808                 :            :     }
    1809                 :            : 
    1810                 :          2 :     ds_destroy(&ds);
    1811         [ +  - ]:          2 :     if (stream != stdin) {
    1812                 :          2 :         fclose(stream);
    1813                 :            :     }
    1814                 :            : 
    1815         [ -  + ]:          2 :     if (error) {
    1816                 :          0 :         char *err_msg = xasprintf("%s:%d: %s", file_name, line_number, error);
    1817                 :          0 :         free(error);
    1818                 :            : 
    1819                 :          0 :         free_bundle_msgs(bms, n_bms);
    1820                 :          0 :         return err_msg;
    1821                 :            :     }
    1822                 :          2 :     return NULL;
    1823                 :            : }
    1824                 :            : 
    1825                 :            : char * OVS_WARN_UNUSED_RESULT
    1826                 :         13 : parse_ofp_tlv_table_mod_str(struct ofputil_tlv_table_mod *ttm,
    1827                 :            :                                uint16_t command, const char *s,
    1828                 :            :                                enum ofputil_protocol *usable_protocols)
    1829                 :            : {
    1830                 :         13 :     *usable_protocols = OFPUTIL_P_NXM_OXM_ANY;
    1831                 :            : 
    1832                 :         13 :     ttm->command = command;
    1833                 :         13 :     ovs_list_init(&ttm->mappings);
    1834                 :            : 
    1835         [ +  + ]:         30 :     while (*s) {
    1836                 :         17 :         struct ofputil_tlv_map *map = xmalloc(sizeof *map);
    1837                 :            :         int n;
    1838                 :            : 
    1839         [ +  + ]:         17 :         if (*s == ',') {
    1840                 :          5 :             s++;
    1841                 :            :         }
    1842                 :            : 
    1843                 :         17 :         ovs_list_push_back(&ttm->mappings, &map->list_node);
    1844                 :            : 
    1845         [ -  + ]:         17 :         if (!ovs_scan(s, "{class=%"SCNi16",type=%"SCNi8",len=%"SCNi8"}->tun_metadata%"SCNi16"%n",
    1846                 :            :                       &map->option_class, &map->option_type, &map->option_len,
    1847                 :            :                       &map->index, &n)) {
    1848                 :          0 :             ofputil_uninit_tlv_table(&ttm->mappings);
    1849                 :          0 :             return xstrdup("invalid tlv mapping");
    1850                 :            :         }
    1851                 :            : 
    1852                 :         17 :         s += n;
    1853                 :            :     }
    1854                 :            : 
    1855                 :         13 :     return NULL;
    1856                 :            : }

Generated by: LCOV version 1.12