LCOV - code coverage report
Current view: top level - lib - ofp-msgs.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 294 343 85.7 %
Date: 2016-09-14 01:02:56 Functions: 44 48 91.7 %
Branches: 127 186 68.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 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                 :            : #include "byte-order.h"
      19                 :            : #include "hash.h"
      20                 :            : #include "openvswitch/hmap.h"
      21                 :            : #include "openflow/nicira-ext.h"
      22                 :            : #include "openflow/openflow.h"
      23                 :            : #include "openvswitch/dynamic-string.h"
      24                 :            : #include "openvswitch/ofp-msgs.h"
      25                 :            : #include "openvswitch/ofpbuf.h"
      26                 :            : #include "openvswitch/vlog.h"
      27                 :            : #include "ovs-thread.h"
      28                 :            : #include "util.h"
      29                 :            : 
      30                 :      20190 : VLOG_DEFINE_THIS_MODULE(ofp_msgs);
      31                 :            : 
      32                 :            : #define OFPT_VENDOR 4
      33                 :            : #define OFPT10_STATS_REQUEST 16
      34                 :            : #define OFPT10_STATS_REPLY 17
      35                 :            : #define OFPT11_STATS_REQUEST 18
      36                 :            : #define OFPT11_STATS_REPLY 19
      37                 :            : #define OFPST_VENDOR 0xffff
      38                 :            : 
      39                 :            : /* Vendor extension message. */
      40                 :            : struct ofp_vendor_header {
      41                 :            :     struct ofp_header header;   /* OFPT_VENDOR. */
      42                 :            :     ovs_be32 vendor;            /* Vendor ID:
      43                 :            :                                  * - MSB 0: low-order bytes are IEEE OUI.
      44                 :            :                                  * - MSB != 0: defined by OpenFlow
      45                 :            :                                  *   consortium. */
      46                 :            : 
      47                 :            :     /* In theory everything after 'vendor' is vendor specific.  In practice,
      48                 :            :      * the vendors we support put a 32-bit subtype here.  We'll change this
      49                 :            :      * structure if we start adding support for other vendor formats. */
      50                 :            :     ovs_be32 subtype;           /* Vendor-specific subtype. */
      51                 :            : 
      52                 :            :     /* Followed by vendor-defined additional data. */
      53                 :            : };
      54                 :            : OFP_ASSERT(sizeof(struct ofp_vendor_header) == 16);
      55                 :            : 
      56                 :            : /* Statistics request or reply message. */
      57                 :            : struct ofp10_stats_msg {
      58                 :            :     struct ofp_header header;
      59                 :            :     ovs_be16 type;              /* One of the OFPST_* constants. */
      60                 :            :     ovs_be16 flags;             /* Requests: always 0.
      61                 :            :                                  * Replies: 0 or OFPSF_REPLY_MORE. */
      62                 :            : };
      63                 :            : OFP_ASSERT(sizeof(struct ofp10_stats_msg) == 12);
      64                 :            : 
      65                 :            : /* Vendor extension stats message. */
      66                 :            : struct ofp10_vendor_stats_msg {
      67                 :            :     struct ofp10_stats_msg osm; /* Type OFPST_VENDOR. */
      68                 :            :     ovs_be32 vendor;            /* Vendor ID:
      69                 :            :                                  * - MSB 0: low-order bytes are IEEE OUI.
      70                 :            :                                  * - MSB != 0: defined by OpenFlow
      71                 :            :                                  *   consortium. */
      72                 :            :     /* Followed by vendor-defined arbitrary additional data. */
      73                 :            : };
      74                 :            : OFP_ASSERT(sizeof(struct ofp10_vendor_stats_msg) == 16);
      75                 :            : 
      76                 :            : struct ofp11_stats_msg {
      77                 :            :     struct ofp_header header;
      78                 :            :     ovs_be16 type;              /* One of the OFPST_* constants. */
      79                 :            :     ovs_be16 flags;             /* OFPSF_REQ_* flags (none yet defined). */
      80                 :            :     uint8_t pad[4];
      81                 :            :     /* Followed by the body of the request. */
      82                 :            : };
      83                 :            : OFP_ASSERT(sizeof(struct ofp11_stats_msg) == 16);
      84                 :            : 
      85                 :            : /* Vendor extension stats message. */
      86                 :            : struct ofp11_vendor_stats_msg {
      87                 :            :     struct ofp11_stats_msg osm; /* Type OFPST_VENDOR. */
      88                 :            :     ovs_be32 vendor;            /* Vendor ID:
      89                 :            :                                  * - MSB 0: low-order bytes are IEEE OUI.
      90                 :            :                                  * - MSB != 0: defined by OpenFlow
      91                 :            :                                  *   consortium. */
      92                 :            : 
      93                 :            :     /* In theory everything after 'vendor' is vendor specific.  In practice,
      94                 :            :      * the vendors we support put a 32-bit subtype here.  We'll change this
      95                 :            :      * structure if we start adding support for other vendor formats. */
      96                 :            :     ovs_be32 subtype;           /* Vendor-specific subtype. */
      97                 :            : 
      98                 :            :     /* Followed by vendor-defined additional data. */
      99                 :            : };
     100                 :            : OFP_ASSERT(sizeof(struct ofp11_vendor_stats_msg) == 24);
     101                 :            : 
     102                 :            : /* Header for Nicira vendor stats request and reply messages in OpenFlow
     103                 :            :  * 1.0. */
     104                 :            : struct nicira10_stats_msg {
     105                 :            :     struct ofp10_vendor_stats_msg vsm; /* Vendor NX_VENDOR_ID. */
     106                 :            :     ovs_be32 subtype;           /* One of NXST_* below. */
     107                 :            :     uint8_t pad[4];             /* Align to 64-bits. */
     108                 :            : };
     109                 :            : OFP_ASSERT(sizeof(struct nicira10_stats_msg) == 24);
     110                 :            : 
     111                 :            : /* A thin abstraction of OpenFlow headers:
     112                 :            :  *
     113                 :            :  *   - 'version' and 'type' come straight from struct ofp_header, so these are
     114                 :            :  *     always present and meaningful.
     115                 :            :  *
     116                 :            :  *   - 'stat' comes from the 'type' member in statistics messages only.  It is
     117                 :            :  *     meaningful, therefore, only if 'version' and 'type' taken together
     118                 :            :  *     specify a statistics request or reply.  Otherwise it is 0.
     119                 :            :  *
     120                 :            :  *   - 'vendor' is meaningful only for vendor messages, that is, if 'version'
     121                 :            :  *     and 'type' specify a vendor message or if 'version' and 'type' specify
     122                 :            :  *     a statistics message and 'stat' specifies a vendor statistic type.
     123                 :            :  *     Otherwise it is 0.
     124                 :            :  *
     125                 :            :  *   - 'subtype' is meaningful only for vendor messages and otherwise 0.  It
     126                 :            :  *     specifies a vendor-defined subtype.  There is no standard format for
     127                 :            :  *     these but 32 bits seems like it should be enough. */
     128                 :            : struct ofphdrs {
     129                 :            :     uint8_t version;            /* From ofp_header. */
     130                 :            :     uint8_t type;               /* From ofp_header. */
     131                 :            :     uint16_t stat;              /* From ofp10_stats_msg or ofp11_stats_msg. */
     132                 :            :     uint32_t vendor;            /* From ofp_vendor_header,
     133                 :            :                                  * ofp10_vendor_stats_msg, or
     134                 :            :                                  * ofp11_vendor_stats_msg. */
     135                 :            :     uint32_t subtype;           /* From nicira_header, nicira10_stats_msg, or
     136                 :            :                                  * nicira11_stats_msg. */
     137                 :            : };
     138                 :            : BUILD_ASSERT_DECL(sizeof(struct ofphdrs) == 12);
     139                 :            : 
     140                 :            : /* A mapping from OpenFlow headers to OFPRAW_*.  */
     141                 :            : struct raw_instance {
     142                 :            :     struct hmap_node hmap_node; /* In 'raw_instance_map'. */
     143                 :            :     struct ofphdrs hdrs;        /* Key. */
     144                 :            :     enum ofpraw raw;            /* Value. */
     145                 :            :     unsigned int hdrs_len;      /* ofphdrs_len(hdrs). */
     146                 :            : };
     147                 :            : 
     148                 :            : /* Information about a particular 'enum ofpraw'. */
     149                 :            : struct raw_info {
     150                 :            :     /* All possible instantiations of this OFPRAW_* into OpenFlow headers. */
     151                 :            :     struct raw_instance *instances; /* min_version - max_version + 1 elems. */
     152                 :            :     uint8_t min_version;
     153                 :            :     uint8_t max_version;
     154                 :            : 
     155                 :            :     unsigned int min_body;
     156                 :            :     unsigned int extra_multiple;
     157                 :            :     enum ofptype type;
     158                 :            :     const char *name;
     159                 :            : };
     160                 :            : 
     161                 :            : /* All understood OpenFlow message types, indexed by their 'struct ofphdrs'. */
     162                 :            : static struct hmap raw_instance_map;
     163                 :            : #include "ofp-msgs.inc"
     164                 :            : 
     165                 :            : static ovs_be32 alloc_xid(void);
     166                 :            : 
     167                 :            : /* ofphdrs functions. */
     168                 :            : static uint32_t ofphdrs_hash(const struct ofphdrs *);
     169                 :            : static bool ofphdrs_equal(const struct ofphdrs *a, const struct ofphdrs *b);
     170                 :            : static enum ofperr ofphdrs_decode(struct ofphdrs *,
     171                 :            :                                   const struct ofp_header *oh, size_t length);
     172                 :            : static void ofphdrs_decode_assert(struct ofphdrs *,
     173                 :            :                                   const struct ofp_header *oh, size_t length);
     174                 :            : size_t ofphdrs_len(const struct ofphdrs *);
     175                 :            : 
     176                 :            : static const struct raw_info *raw_info_get(enum ofpraw);
     177                 :            : static struct raw_instance *raw_instance_get(const struct raw_info *,
     178                 :            :                                              uint8_t version);
     179                 :            : 
     180                 :            : static enum ofperr ofpraw_from_ofphdrs(enum ofpraw *, const struct ofphdrs *);
     181                 :            : 
     182                 :            : /* Returns a transaction ID to use for an outgoing OpenFlow message. */
     183                 :            : static ovs_be32
     184                 :      59848 : alloc_xid(void)
     185                 :            : {
     186                 :            :     static atomic_count next_xid = ATOMIC_COUNT_INIT(1);
     187                 :            : 
     188                 :      59848 :     return htonl(atomic_count_inc(&next_xid));
     189                 :            : }
     190                 :            : 
     191                 :            : static uint32_t
     192                 :    6883490 : ofphdrs_hash(const struct ofphdrs *hdrs)
     193                 :            : {
     194                 :            :     BUILD_ASSERT_DECL(sizeof *hdrs % 4 == 0);
     195                 :    6883490 :     return hash_bytes32((const uint32_t *) hdrs, sizeof *hdrs, 0);
     196                 :            : }
     197                 :            : 
     198                 :            : static bool
     199                 :     367516 : ofphdrs_equal(const struct ofphdrs *a, const struct ofphdrs *b)
     200                 :            : {
     201                 :     367516 :     return !memcmp(a, b, sizeof *a);
     202                 :            : }
     203                 :            : 
     204                 :            : static void
     205                 :          0 : log_bad_vendor(uint32_t vendor)
     206                 :            : {
     207                 :            :     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
     208                 :            : 
     209         [ #  # ]:          0 :     VLOG_WARN_RL(&rl, "OpenFlow message has unknown vendor %#"PRIx32, vendor);
     210                 :          0 : }
     211                 :            : 
     212                 :            : static enum ofperr
     213                 :     367971 : ofphdrs_decode(struct ofphdrs *hdrs,
     214                 :            :                const struct ofp_header *oh, size_t length)
     215                 :            : {
     216                 :     367971 :     memset(hdrs, 0, sizeof *hdrs);
     217         [ -  + ]:     367971 :     if (length < sizeof *oh) {
     218                 :          0 :         return OFPERR_OFPBRC_BAD_LEN;
     219                 :            :     }
     220                 :            : 
     221                 :            :     /* Get base message version and type (OFPT_*). */
     222                 :     367971 :     hdrs->version = oh->version;
     223                 :     367971 :     hdrs->type = oh->type;
     224                 :            : 
     225         [ +  + ]:     367971 :     if (hdrs->type == OFPT_VENDOR) {
     226                 :            :         /* Get vendor. */
     227                 :            :         const struct ofp_vendor_header *ovh;
     228                 :            : 
     229         [ -  + ]:      49518 :         if (length < sizeof *ovh) {
     230                 :          0 :             return OFPERR_OFPBRC_BAD_LEN;
     231                 :            :         }
     232                 :            : 
     233                 :      49518 :         ovh = (const struct ofp_vendor_header *) oh;
     234                 :      49518 :         hdrs->vendor = ntohl(ovh->vendor);
     235 [ +  + ][ +  - ]:      49518 :         if (hdrs->vendor == NX_VENDOR_ID || hdrs->vendor == ONF_VENDOR_ID) {
     236                 :      49518 :             hdrs->subtype = ntohl(ovh->subtype);
     237                 :            :         } else {
     238                 :          0 :             log_bad_vendor(hdrs->vendor);
     239                 :          0 :             return OFPERR_OFPBRC_BAD_VENDOR;
     240                 :            :         }
     241         [ +  + ]:     318453 :     } else if (hdrs->version == OFP10_VERSION
     242 [ +  + ][ +  + ]:     160545 :                && (hdrs->type == OFPT10_STATS_REQUEST ||
     243                 :      91653 :                    hdrs->type == OFPT10_STATS_REPLY)) {
     244                 :            :         const struct ofp10_stats_msg *osm;
     245                 :            : 
     246                 :            :         /* Get statistic type (OFPST_*). */
     247         [ +  + ]:      91654 :         if (length < sizeof *osm) {
     248                 :          1 :             return OFPERR_OFPBRC_BAD_LEN;
     249                 :            :         }
     250                 :      91653 :         osm = (const struct ofp10_stats_msg *) oh;
     251                 :      91653 :         hdrs->stat = ntohs(osm->type);
     252                 :            : 
     253         [ +  + ]:      91653 :         if (hdrs->stat == OFPST_VENDOR) {
     254                 :            :             /* Get vendor. */
     255                 :            :             const struct ofp10_vendor_stats_msg *ovsm;
     256                 :            : 
     257         [ -  + ]:      90797 :             if (length < sizeof *ovsm) {
     258                 :          0 :                 return OFPERR_OFPBRC_BAD_LEN;
     259                 :            :             }
     260                 :            : 
     261                 :      90797 :             ovsm = (const struct ofp10_vendor_stats_msg *) oh;
     262                 :      90797 :             hdrs->vendor = ntohl(ovsm->vendor);
     263         [ +  - ]:      90797 :             if (hdrs->vendor == NX_VENDOR_ID) {
     264                 :            :                 /* Get Nicira statistic type (NXST_*). */
     265                 :            :                 const struct nicira10_stats_msg *nsm;
     266                 :            : 
     267         [ -  + ]:      90797 :                 if (length < sizeof *nsm) {
     268                 :          0 :                     return OFPERR_OFPBRC_BAD_LEN;
     269                 :            :                 }
     270                 :      90797 :                 nsm = (const struct nicira10_stats_msg *) oh;
     271                 :      90797 :                 hdrs->subtype = ntohl(nsm->subtype);
     272                 :            :             } else {
     273                 :          0 :                 log_bad_vendor(hdrs->vendor);
     274                 :          0 :                 return OFPERR_OFPBRC_BAD_VENDOR;
     275                 :            :             }
     276                 :            :         }
     277         [ +  + ]:     226799 :     } else if (hdrs->version != OFP10_VERSION
     278 [ +  + ][ +  + ]:     157908 :                && (hdrs->type == OFPT11_STATS_REQUEST ||
     279                 :     156010 :                    hdrs->type == OFPT11_STATS_REPLY)) {
     280                 :            :         const struct ofp11_stats_msg *osm;
     281                 :            : 
     282                 :            :         /* Get statistic type (OFPST_*). */
     283         [ -  + ]:      10277 :         if (length < sizeof *osm) {
     284                 :          0 :             return OFPERR_OFPBRC_BAD_LEN;
     285                 :            :         }
     286                 :      10277 :         osm = (const struct ofp11_stats_msg *) oh;
     287                 :      10277 :         hdrs->stat = ntohs(osm->type);
     288                 :            : 
     289         [ -  + ]:      10277 :         if (hdrs->stat == OFPST_VENDOR) {
     290                 :            :             /* Get vendor. */
     291                 :            :             const struct ofp11_vendor_stats_msg *ovsm;
     292                 :            : 
     293         [ #  # ]:          0 :             if (length < sizeof *ovsm) {
     294                 :          0 :                 return OFPERR_OFPBRC_BAD_LEN;
     295                 :            :             }
     296                 :            : 
     297                 :          0 :             ovsm = (const struct ofp11_vendor_stats_msg *) oh;
     298                 :          0 :             hdrs->vendor = ntohl(ovsm->vendor);
     299 [ #  # ][ #  # ]:          0 :             if (hdrs->vendor == NX_VENDOR_ID ||
     300                 :          0 :                 hdrs->vendor == ONF_VENDOR_ID) {
     301                 :          0 :                 hdrs->subtype = ntohl(ovsm->subtype);
     302                 :            :             } else {
     303                 :          0 :                 log_bad_vendor(hdrs->vendor);
     304                 :          0 :                 return OFPERR_OFPBRC_BAD_VENDOR;
     305                 :            :             }
     306                 :            :         }
     307                 :            :     }
     308                 :            : 
     309                 :     367970 :     return 0;
     310                 :            : }
     311                 :            : 
     312                 :            : static void
     313                 :       1566 : ofphdrs_decode_assert(struct ofphdrs *hdrs,
     314                 :            :                       const struct ofp_header *oh, size_t length)
     315                 :            : {
     316                 :       1566 :     enum ofperr error = ofphdrs_decode(hdrs, oh, length);
     317         [ -  + ]:       1566 :     ovs_assert(!error);
     318                 :       1566 : }
     319                 :            : 
     320                 :            : static bool
     321                 :      26295 : ofp_is_stat_request(enum ofp_version version, uint8_t type)
     322                 :            : {
     323      [ +  +  + ]:      26295 :     switch (version) {
     324                 :            :     case OFP10_VERSION:
     325                 :        333 :         return type == OFPT10_STATS_REQUEST;
     326                 :            :     case OFP11_VERSION:
     327                 :            :     case OFP12_VERSION:
     328                 :            :     case OFP13_VERSION:
     329                 :            :     case OFP14_VERSION:
     330                 :            :     case OFP15_VERSION:
     331                 :            :     case OFP16_VERSION:
     332                 :      25948 :         return type == OFPT11_STATS_REQUEST;
     333                 :            :     }
     334                 :            : 
     335                 :         14 :     return false;
     336                 :            : }
     337                 :            : 
     338                 :            : static bool
     339                 :         14 : ofp_is_stat_reply(enum ofp_version version, uint8_t type)
     340                 :            : {
     341      [ -  -  + ]:         14 :     switch (version) {
     342                 :            :     case OFP10_VERSION:
     343                 :          0 :         return type == OFPT10_STATS_REPLY;
     344                 :            :     case OFP11_VERSION:
     345                 :            :     case OFP12_VERSION:
     346                 :            :     case OFP13_VERSION:
     347                 :            :     case OFP14_VERSION:
     348                 :            :     case OFP15_VERSION:
     349                 :            :     case OFP16_VERSION:
     350                 :          0 :         return type == OFPT11_STATS_REPLY;
     351                 :            :     }
     352                 :            : 
     353                 :         14 :     return false;
     354                 :            : }
     355                 :            : 
     356                 :            : static bool
     357                 :         14 : ofp_is_stat(enum ofp_version version, uint8_t type)
     358                 :            : {
     359   [ +  -  -  + ]:         28 :     return (ofp_is_stat_request(version, type) ||
     360                 :         14 :             ofp_is_stat_reply(version, type));
     361                 :            : }
     362                 :            : 
     363                 :            : static bool
     364                 :         14 : ofphdrs_is_stat(const struct ofphdrs *hdrs)
     365                 :            : {
     366                 :         14 :     return ofp_is_stat(hdrs->version, hdrs->type);
     367                 :            : }
     368                 :            : 
     369                 :            : size_t
     370                 :    6517530 : ofphdrs_len(const struct ofphdrs *hdrs)
     371                 :            : {
     372         [ +  + ]:    6517530 :     if (hdrs->type == OFPT_VENDOR) {
     373                 :     571118 :         return sizeof(struct ofp_vendor_header);
     374                 :            :     }
     375                 :            : 
     376      [ +  +  + ]:    5946412 :     switch ((enum ofp_version) hdrs->version) {
     377                 :            :     case OFP10_VERSION:
     378 [ +  + ][ +  + ]:     184276 :         if (hdrs->type == OFPT10_STATS_REQUEST ||
     379                 :     132814 :             hdrs->type == OFPT10_STATS_REPLY) {
     380                 :     102879 :             return (hdrs->stat == OFPST_VENDOR
     381                 :            :                     ? sizeof(struct nicira10_stats_msg)
     382         [ +  + ]:     102879 :                     : sizeof(struct ofp10_stats_msg));
     383                 :            :         }
     384                 :      81397 :         break;
     385                 :            : 
     386                 :            :     case OFP11_VERSION:
     387                 :            :     case OFP12_VERSION:
     388                 :            :     case OFP13_VERSION:
     389                 :            :     case OFP14_VERSION:
     390                 :            :     case OFP15_VERSION:
     391                 :            :     case OFP16_VERSION:
     392 [ +  + ][ +  + ]:    1512408 :         if (hdrs->type == OFPT11_STATS_REQUEST ||
     393                 :    1101033 :             hdrs->type == OFPT11_STATS_REPLY) {
     394                 :     822675 :             return (hdrs->stat == OFPST_VENDOR
     395                 :            :                     ? sizeof(struct ofp11_vendor_stats_msg)
     396         [ +  + ]:     822675 :                     : sizeof(struct ofp11_stats_msg));
     397                 :            :         }
     398                 :     689733 :         break;
     399                 :            :     }
     400                 :            : 
     401                 :    5020858 :     return sizeof(struct ofp_header);
     402                 :            : }
     403                 :            : 
     404                 :            : /* Determines the OFPRAW_* type of the OpenFlow message at 'oh', which has
     405                 :            :  * length 'oh->length'.  (The caller must ensure that 'oh->length' bytes of
     406                 :            :  * data are readable at 'oh'.)  On success, returns 0 and stores the type into
     407                 :            :  * '*raw'.  On failure, returns an OFPERR_* error code and zeros '*raw'.
     408                 :            :  *
     409                 :            :  * This function checks that 'oh' is a valid length for its particular type of
     410                 :            :  * message, and returns an error if not. */
     411                 :            : enum ofperr
     412                 :     243277 : ofpraw_decode(enum ofpraw *raw, const struct ofp_header *oh)
     413                 :            : {
     414                 :     243277 :     struct ofpbuf msg = ofpbuf_const_initializer(oh, ntohs(oh->length));
     415                 :     243277 :     return ofpraw_pull(raw, &msg);
     416                 :            : }
     417                 :            : 
     418                 :            : /* Does the same job as ofpraw_decode(), except that it assert-fails if
     419                 :            :  * ofpraw_decode() would have reported an error.  Thus, it's able to use the
     420                 :            :  * return value for the OFPRAW_* message type instead of an error code.
     421                 :            :  *
     422                 :            :  * (It only makes sense to use this function if you previously called
     423                 :            :  * ofpraw_decode() on the message and thus know that it's OK.) */
     424                 :            : enum ofpraw
     425                 :         69 : ofpraw_decode_assert(const struct ofp_header *oh)
     426                 :            : {
     427                 :            :     enum ofperr error;
     428                 :            :     enum ofpraw raw;
     429                 :            : 
     430                 :         69 :     error = ofpraw_decode(&raw, oh);
     431         [ -  + ]:         69 :     ovs_assert(!error);
     432                 :         69 :     return raw;
     433                 :            : }
     434                 :            : 
     435                 :            : /* Determines the OFPRAW_* type of the OpenFlow message in 'msg', which starts
     436                 :            :  * at 'msg->data' and has length 'msg->size' bytes.  On success,
     437                 :            :  * returns 0 and stores the type into '*rawp'.  On failure, returns an OFPERR_*
     438                 :            :  * error code and zeros '*rawp'.
     439                 :            :  *
     440                 :            :  * This function checks that the message has a valid length for its particular
     441                 :            :  * type of message, and returns an error if not.
     442                 :            :  *
     443                 :            :  * In addition to setting '*rawp', this function pulls off the OpenFlow header
     444                 :            :  * (including the stats headers, vendor header, and any subtype header) with
     445                 :            :  * ofpbuf_pull().  It also sets 'msg->header' to the start of the OpenFlow
     446                 :            :  * header and 'msg->msg' just beyond the headers (that is, to the final value
     447                 :            :  * of msg->data). */
     448                 :            : enum ofperr
     449                 :     345156 : ofpraw_pull(enum ofpraw *rawp, struct ofpbuf *msg)
     450                 :            : {
     451                 :            :     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     452                 :            : 
     453                 :            :     const struct raw_instance *instance;
     454                 :            :     const struct raw_info *info;
     455                 :            :     struct ofphdrs hdrs;
     456                 :            : 
     457                 :            :     unsigned int min_len;
     458                 :            :     unsigned int len;
     459                 :            : 
     460                 :            :     enum ofperr error;
     461                 :            :     enum ofpraw raw;
     462                 :            : 
     463                 :            :     /* Set default outputs. */
     464                 :     345156 :     msg->header = msg->data;
     465                 :     345156 :     msg->msg = msg->header;
     466                 :     345156 :     *rawp = 0;
     467                 :            : 
     468                 :     345156 :     len = msg->size;
     469                 :     345156 :     error = ofphdrs_decode(&hdrs, msg->data, len);
     470         [ -  + ]:     345156 :     if (error) {
     471                 :          0 :         return error;
     472                 :            :     }
     473                 :            : 
     474                 :     345156 :     error = ofpraw_from_ofphdrs(&raw, &hdrs);
     475         [ +  + ]:     345156 :     if (error) {
     476                 :         10 :         return error;
     477                 :            :     }
     478                 :            : 
     479                 :     345146 :     info = raw_info_get(raw);
     480                 :     345146 :     instance = raw_instance_get(info, hdrs.version);
     481                 :     345146 :     msg->header = ofpbuf_pull(msg, instance->hdrs_len);
     482                 :     345146 :     msg->msg = msg->data;
     483                 :            : 
     484                 :     345146 :     min_len = instance->hdrs_len + info->min_body;
     485      [ +  +  + ]:     345146 :     switch (info->extra_multiple) {
     486                 :            :     case 0:
     487         [ -  + ]:      54658 :         if (len != min_len) {
     488         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "received %s with incorrect length %u (expected "
     489                 :            :                          "length %u)", info->name, len, min_len);
     490                 :          0 :             return OFPERR_OFPBRC_BAD_LEN;
     491                 :            :         }
     492                 :      54658 :         break;
     493                 :            : 
     494                 :            :     case 1:
     495         [ -  + ]:      68643 :         if (len < min_len) {
     496         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "received %s with incorrect length %u (expected "
     497                 :            :                          "length at least %u bytes)",
     498                 :            :                          info->name, len, min_len);
     499                 :          0 :             return OFPERR_OFPBRC_BAD_LEN;
     500                 :            :         }
     501                 :      68643 :         break;
     502                 :            : 
     503                 :            :     default:
     504 [ +  - ][ +  + ]:     221845 :         if (len < min_len || (len - min_len) % info->extra_multiple) {
     505         [ +  - ]:          2 :             VLOG_WARN_RL(&rl, "received %s with incorrect length %u (must be "
     506                 :            :                          "exactly %u bytes or longer by an integer multiple "
     507                 :            :                          "of %u bytes)",
     508                 :            :                          info->name, len, min_len, info->extra_multiple);
     509                 :          2 :             return OFPERR_OFPBRC_BAD_LEN;
     510                 :            :         }
     511                 :     221843 :         break;
     512                 :            :     }
     513                 :            : 
     514                 :     345144 :     *rawp = raw;
     515                 :     345156 :     return 0;
     516                 :            : }
     517                 :            : 
     518                 :            : /* Does the same job as ofpraw_pull(), except that it assert-fails if
     519                 :            :  * ofpraw_pull() would have reported an error.  Thus, it's able to use the
     520                 :            :  * return value for the OFPRAW_* message type instead of an error code.
     521                 :            :  *
     522                 :            :  * (It only makes sense to use this function if you previously called
     523                 :            :  * ofpraw_decode() on the message and thus know that it's OK.) */
     524                 :            : enum ofpraw
     525                 :      99666 : ofpraw_pull_assert(struct ofpbuf *msg)
     526                 :            : {
     527                 :            :     enum ofperr error;
     528                 :            :     enum ofpraw raw;
     529                 :            : 
     530                 :      99666 :     error = ofpraw_pull(&raw, msg);
     531         [ -  + ]:      99666 :     ovs_assert(!error);
     532                 :      99666 :     return raw;
     533                 :            : }
     534                 :            : 
     535                 :            : /* Determines the OFPRAW_* type of the OpenFlow message that starts at 'oh' and
     536                 :            :  * has length 'length' bytes.  On success, returns 0 and stores the type into
     537                 :            :  * '*rawp'.  On failure, returns an OFPERR_* error code and zeros '*rawp'.
     538                 :            :  *
     539                 :            :  * Unlike other functions for decoding message types, this one is not picky
     540                 :            :  * about message length.  For example, it will successfully decode a message
     541                 :            :  * whose body is shorter than the minimum length for a message of its type.
     542                 :            :  * Thus, this is the correct function to use for decoding the type of a message
     543                 :            :  * that might have been truncated, such as the payload of an OpenFlow error
     544                 :            :  * message (which is allowed to be truncated to 64 bytes). */
     545                 :            : enum ofperr
     546                 :      21249 : ofpraw_decode_partial(enum ofpraw *raw,
     547                 :            :                       const struct ofp_header *oh, size_t length)
     548                 :            : {
     549                 :            :     struct ofphdrs hdrs;
     550                 :            :     enum ofperr error;
     551                 :            : 
     552                 :      21249 :     error = ofphdrs_decode(&hdrs, oh, length);
     553         [ +  + ]:      21249 :     if (!error) {
     554                 :      21248 :         error = ofpraw_from_ofphdrs(raw, &hdrs);
     555                 :            :     }
     556                 :            : 
     557         [ +  + ]:      21249 :     if (error) {
     558                 :          1 :         *raw = 0;
     559                 :            :     }
     560                 :      21249 :     return error;
     561                 :            : }
     562                 :            : 
     563                 :            : /* Encoding messages using OFPRAW_* values. */
     564                 :            : 
     565                 :            : static void ofpraw_put__(enum ofpraw, uint8_t version, ovs_be32 xid,
     566                 :            :                          size_t extra_tailroom, struct ofpbuf *);
     567                 :            : 
     568                 :            : /* Allocates and returns a new ofpbuf that contains an OpenFlow header for
     569                 :            :  * 'raw' with OpenFlow version 'version' and a fresh OpenFlow transaction ID.
     570                 :            :  * The ofpbuf has enough tailroom for the minimum body length of 'raw', plus
     571                 :            :  * 'extra_tailroom' additional bytes.
     572                 :            :  *
     573                 :            :  * Each 'raw' value is valid only for certain OpenFlow versions.  The caller
     574                 :            :  * must specify a valid (raw, version) pair.
     575                 :            :  *
     576                 :            :  * In the returned ofpbuf, 'header' points to the beginning of the
     577                 :            :  * OpenFlow header and 'msg' points just after it, to where the
     578                 :            :  * message's body will start.  The caller must actually allocate the
     579                 :            :  * body into the space reserved for it, e.g. with ofpbuf_put_uninit().
     580                 :            :  *
     581                 :            :  * The caller owns the returned ofpbuf and must free it when it is no longer
     582                 :            :  * needed, e.g. with ofpbuf_delete(). */
     583                 :            : struct ofpbuf *
     584                 :      59844 : ofpraw_alloc(enum ofpraw raw, uint8_t version, size_t extra_tailroom)
     585                 :            : {
     586                 :      59844 :     return ofpraw_alloc_xid(raw, version, alloc_xid(), extra_tailroom);
     587                 :            : }
     588                 :            : 
     589                 :            : /* Same as ofpraw_alloc() but the caller provides the transaction ID. */
     590                 :            : struct ofpbuf *
     591                 :      81865 : ofpraw_alloc_xid(enum ofpraw raw, uint8_t version, ovs_be32 xid,
     592                 :            :                  size_t extra_tailroom)
     593                 :            : {
     594                 :      81865 :     struct ofpbuf *buf = ofpbuf_new(0);
     595                 :      81865 :     ofpraw_put__(raw, version, xid, extra_tailroom, buf);
     596                 :      81865 :     return buf;
     597                 :            : }
     598                 :            : 
     599                 :            : /* Same as ofpraw_alloc(), but obtains the OpenFlow version and transaction ID
     600                 :            :  * from 'request->version' and 'request->xid', respectively.
     601                 :            :  *
     602                 :            :  * Even though the version comes from 'request->version', the caller must still
     603                 :            :  * know what it is doing, by specifying a valid pairing of 'raw' and
     604                 :            :  * 'request->version', just like ofpraw_alloc(). */
     605                 :            : struct ofpbuf *
     606                 :      16221 : ofpraw_alloc_reply(enum ofpraw raw, const struct ofp_header *request,
     607                 :            :                    size_t extra_tailroom)
     608                 :            : {
     609                 :      16221 :     return ofpraw_alloc_xid(raw, request->version, request->xid,
     610                 :            :                             extra_tailroom);
     611                 :            : }
     612                 :            : 
     613                 :            : /* Allocates and returns a new ofpbuf that contains an OpenFlow header that is
     614                 :            :  * a stats reply to the stats request in 'request', using the same OpenFlow
     615                 :            :  * version and transaction ID as 'request'.  The ofpbuf has enough tailroom for
     616                 :            :  * the stats reply's minimum body length, plus 'extra_tailroom' additional
     617                 :            :  * bytes.
     618                 :            :  *
     619                 :            :  * 'request' must be a stats request, that is, an OFPRAW_OFPST* or OFPRAW_NXST*
     620                 :            :  * value.  Every stats request has a corresponding reply, so the (raw, version)
     621                 :            :  * pairing pitfalls of the other ofpraw_alloc_*() functions don't apply here.
     622                 :            :  *
     623                 :            :  * In the returned ofpbuf, 'header' points to the beginning of the
     624                 :            :  * OpenFlow header and 'msg' points just after it, to where the
     625                 :            :  * message's body will start.  The caller must actually allocate the
     626                 :            :  * body into the space reserved for it, e.g. with ofpbuf_put_uninit().
     627                 :            :  *
     628                 :            :  * The caller owns the returned ofpbuf and must free it when it is no longer
     629                 :            :  * needed, e.g. with ofpbuf_delete(). */
     630                 :            : struct ofpbuf *
     631                 :        575 : ofpraw_alloc_stats_reply(const struct ofp_header *request,
     632                 :            :                          size_t extra_tailroom)
     633                 :            : {
     634                 :            :     enum ofpraw request_raw;
     635                 :            :     enum ofpraw reply_raw;
     636                 :            :     enum ofperr error;
     637                 :            : 
     638                 :        575 :     error = ofpraw_decode_partial(&request_raw, request,
     639                 :        575 :                                   ntohs(request->length));
     640         [ -  + ]:        575 :     ovs_assert(!error);
     641                 :            : 
     642                 :        575 :     reply_raw = ofpraw_stats_request_to_reply(request_raw, request->version);
     643         [ -  + ]:        575 :     ovs_assert(reply_raw);
     644                 :            : 
     645                 :        575 :     return ofpraw_alloc_reply(reply_raw, request, extra_tailroom);
     646                 :            : }
     647                 :            : 
     648                 :            : /* Appends to 'buf' an OpenFlow header for 'raw' with OpenFlow version
     649                 :            :  * 'version' and a fresh OpenFlow transaction ID.  Preallocates enough tailroom
     650                 :            :  * in 'buf' for the minimum body length of 'raw', plus 'extra_tailroom'
     651                 :            :  * additional bytes.
     652                 :            :  *
     653                 :            :  * Each 'raw' value is valid only for certain OpenFlow versions.  The caller
     654                 :            :  * must specify a valid (raw, version) pair.
     655                 :            :  *
     656                 :            :  * Upon return, 'buf->header' points to the beginning of the OpenFlow header
     657                 :            :  * and 'buf->msg' points just after it, to where the message's body will start.
     658                 :            :  * The caller must actually allocating the body into the space reserved for it,
     659                 :            :  * e.g. with ofpbuf_put_uninit(). */
     660                 :            : void
     661                 :          4 : ofpraw_put(enum ofpraw raw, uint8_t version, struct ofpbuf *buf)
     662                 :            : {
     663                 :          4 :     ofpraw_put__(raw, version, alloc_xid(), 0, buf);
     664                 :          4 : }
     665                 :            : 
     666                 :            : /* Same as ofpraw_put() but the caller provides the transaction ID. */
     667                 :            : void
     668                 :          0 : ofpraw_put_xid(enum ofpraw raw, uint8_t version, ovs_be32 xid,
     669                 :            :                struct ofpbuf *buf)
     670                 :            : {
     671                 :          0 :     ofpraw_put__(raw, version, xid, 0, buf);
     672                 :          0 : }
     673                 :            : 
     674                 :            : /* Same as ofpraw_put(), but obtains the OpenFlow version and transaction ID
     675                 :            :  * from 'request->version' and 'request->xid', respectively.
     676                 :            :  *
     677                 :            :  * Even though the version comes from 'request->version', the caller must still
     678                 :            :  * know what it is doing, by specifying a valid pairing of 'raw' and
     679                 :            :  * 'request->version', just like ofpraw_put(). */
     680                 :            : void
     681                 :          0 : ofpraw_put_reply(enum ofpraw raw, const struct ofp_header *request,
     682                 :            :                  struct ofpbuf *buf)
     683                 :            : {
     684                 :          0 :     ofpraw_put__(raw, request->version, request->xid, 0, buf);
     685                 :          0 : }
     686                 :            : 
     687                 :            : /* Appends to 'buf' an OpenFlow header that is a stats reply to the stats
     688                 :            :  * request in 'request', using the same OpenFlow version and transaction ID as
     689                 :            :  * 'request'.  Preallocate enough tailroom in 'buf for the stats reply's
     690                 :            :  * minimum body length, plus 'extra_tailroom' additional bytes.
     691                 :            :  *
     692                 :            :  * 'request' must be a stats request, that is, an OFPRAW_OFPST* or OFPRAW_NXST*
     693                 :            :  * value.  Every stats request has a corresponding reply, so the (raw, version)
     694                 :            :  * pairing pitfalls of the other ofpraw_alloc_*() functions don't apply here.
     695                 :            :  *
     696                 :            :  * In the returned ofpbuf, 'header' points to the beginning of the
     697                 :            :  * OpenFlow header and 'msg' points just after it, to where the
     698                 :            :  * message's body will start.  The caller must actually allocate the
     699                 :            :  * body into the space reserved for it, e.g. with ofpbuf_put_uninit().
     700                 :            :  *
     701                 :            :  * The caller owns the returned ofpbuf and must free it when it is no longer
     702                 :            :  * needed, e.g. with ofpbuf_delete(). */
     703                 :            : void
     704                 :          0 : ofpraw_put_stats_reply(const struct ofp_header *request, struct ofpbuf *buf)
     705                 :            : {
     706                 :            :     enum ofperr error;
     707                 :            :     enum ofpraw raw;
     708                 :            : 
     709                 :          0 :     error = ofpraw_decode_partial(&raw, request, ntohs(request->length));
     710         [ #  # ]:          0 :     ovs_assert(!error);
     711                 :            : 
     712                 :          0 :     raw = ofpraw_stats_request_to_reply(raw, request->version);
     713         [ #  # ]:          0 :     ovs_assert(raw);
     714                 :            : 
     715                 :          0 :     ofpraw_put__(raw, request->version, request->xid, 0, buf);
     716                 :          0 : }
     717                 :            : 
     718                 :            : static void
     719                 :      81869 : ofpraw_put__(enum ofpraw raw, uint8_t version, ovs_be32 xid,
     720                 :            :              size_t extra_tailroom, struct ofpbuf *buf)
     721                 :            : {
     722                 :      81869 :     const struct raw_info *info = raw_info_get(raw);
     723                 :      81869 :     const struct raw_instance *instance = raw_instance_get(info, version);
     724                 :      81869 :     const struct ofphdrs *hdrs = &instance->hdrs;
     725                 :            :     struct ofp_header *oh;
     726                 :            : 
     727                 :      81869 :     ofpbuf_prealloc_tailroom(buf, (instance->hdrs_len + info->min_body
     728                 :            :                                    + extra_tailroom));
     729                 :      81869 :     buf->header = ofpbuf_put_uninit(buf, instance->hdrs_len);
     730                 :      81869 :     buf->msg = ofpbuf_tail(buf);
     731                 :            : 
     732                 :      81869 :     oh = buf->header;
     733                 :      81869 :     oh->version = version;
     734                 :      81869 :     oh->type = hdrs->type;
     735                 :      81869 :     oh->length = htons(buf->size);
     736                 :      81869 :     oh->xid = xid;
     737                 :            : 
     738         [ +  + ]:      81869 :     if (hdrs->type == OFPT_VENDOR) {
     739                 :       9672 :         struct ofp_vendor_header *ovh = buf->header;
     740                 :            : 
     741                 :       9672 :         ovh->vendor = htonl(hdrs->vendor);
     742                 :       9672 :         ovh->subtype = htonl(hdrs->subtype);
     743         [ +  + ]:      72197 :     } else if (version == OFP10_VERSION
     744 [ +  + ][ +  + ]:      36485 :                && (hdrs->type == OFPT10_STATS_REQUEST ||
     745                 :       3288 :                    hdrs->type == OFPT10_STATS_REPLY)) {
     746                 :       3288 :         struct ofp10_stats_msg *osm = buf->header;
     747                 :            : 
     748                 :       3288 :         osm->type = htons(hdrs->stat);
     749                 :       3288 :         osm->flags = htons(0);
     750                 :            : 
     751         [ +  + ]:       3288 :         if (hdrs->stat == OFPST_VENDOR) {
     752                 :       3208 :             struct ofp10_vendor_stats_msg *ovsm = buf->header;
     753                 :            : 
     754                 :       3208 :             ovsm->vendor = htonl(hdrs->vendor);
     755         [ +  - ]:       3208 :             if (hdrs->vendor == NX_VENDOR_ID) {
     756                 :       3208 :                 struct nicira10_stats_msg *nsm = buf->header;
     757                 :            : 
     758                 :       3208 :                 nsm->subtype = htonl(hdrs->subtype);
     759                 :       3208 :                 memset(nsm->pad, 0, sizeof nsm->pad);
     760                 :            :             } else {
     761                 :          0 :                 OVS_NOT_REACHED();
     762                 :            :             }
     763                 :            :         }
     764         [ +  + ]:      68909 :     } else if (version != OFP10_VERSION
     765 [ +  + ][ +  + ]:      35712 :                && (hdrs->type == OFPT11_STATS_REQUEST ||
     766                 :      35432 :                    hdrs->type == OFPT11_STATS_REPLY)) {
     767                 :        540 :         struct ofp11_stats_msg *osm = buf->header;
     768                 :            : 
     769                 :        540 :         osm->type = htons(hdrs->stat);
     770                 :        540 :         osm->flags = htons(0);
     771                 :        540 :         memset(osm->pad, 0, sizeof osm->pad);
     772                 :            : 
     773         [ -  + ]:        540 :         if (hdrs->stat == OFPST_VENDOR) {
     774                 :          0 :             struct ofp11_vendor_stats_msg *ovsm = buf->header;
     775                 :            : 
     776                 :          0 :             ovsm->vendor = htonl(hdrs->vendor);
     777                 :          0 :             ovsm->subtype = htonl(hdrs->subtype);
     778                 :            :         }
     779                 :            :     }
     780                 :      81869 : }
     781                 :            : 
     782                 :            : /* Returns 'raw''s name.
     783                 :            :  *
     784                 :            :  * The name is the name used for 'raw' in the OpenFlow specification.  For
     785                 :            :  * example, ofpraw_get_name(OFPRAW_OFPT10_FEATURES_REPLY) is
     786                 :            :  * "OFPT_FEATURES_REPLY".
     787                 :            :  *
     788                 :            :  * The caller must not modify or free the returned string. */
     789                 :            : const char *
     790                 :     100748 : ofpraw_get_name(enum ofpraw raw)
     791                 :            : {
     792                 :     100748 :     return raw_info_get(raw)->name;
     793                 :            : }
     794                 :            : 
     795                 :            : /* Returns the stats reply that corresponds to 'raw' in the given OpenFlow
     796                 :            :  * 'version'. */
     797                 :            : enum ofpraw
     798                 :       1122 : ofpraw_stats_request_to_reply(enum ofpraw raw, uint8_t version)
     799                 :            : {
     800                 :       1122 :     const struct raw_info *info = raw_info_get(raw);
     801                 :       1122 :     const struct raw_instance *instance = raw_instance_get(info, version);
     802                 :            :     enum ofpraw reply_raw;
     803                 :            :     struct ofphdrs hdrs;
     804                 :            :     enum ofperr error;
     805                 :            : 
     806                 :       1122 :     hdrs = instance->hdrs;
     807      [ +  +  - ]:       1122 :     switch ((enum ofp_version)hdrs.version) {
     808                 :            :     case OFP10_VERSION:
     809         [ -  + ]:        616 :         ovs_assert(hdrs.type == OFPT10_STATS_REQUEST);
     810                 :        616 :         hdrs.type = OFPT10_STATS_REPLY;
     811                 :        616 :         break;
     812                 :            :     case OFP11_VERSION:
     813                 :            :     case OFP12_VERSION:
     814                 :            :     case OFP13_VERSION:
     815                 :            :     case OFP14_VERSION:
     816                 :            :     case OFP15_VERSION:
     817                 :            :     case OFP16_VERSION:
     818         [ -  + ]:        506 :         ovs_assert(hdrs.type == OFPT11_STATS_REQUEST);
     819                 :        506 :         hdrs.type = OFPT11_STATS_REPLY;
     820                 :        506 :         break;
     821                 :            :     default:
     822                 :          0 :         OVS_NOT_REACHED();
     823                 :            :     }
     824                 :            : 
     825                 :       1122 :     error = ofpraw_from_ofphdrs(&reply_raw, &hdrs);
     826         [ -  + ]:       1122 :     ovs_assert(!error);
     827                 :            : 
     828                 :       1122 :     return reply_raw;
     829                 :            : }
     830                 :            : 
     831                 :            : /* Determines the OFPTYPE_* type of the OpenFlow message at 'oh', which has
     832                 :            :  * length 'oh->length'.  (The caller must ensure that 'oh->length' bytes of
     833                 :            :  * data are readable at 'oh'.)  On success, returns 0 and stores the type into
     834                 :            :  * '*typep'.  On failure, returns an OFPERR_* error code and zeros '*typep'.
     835                 :            :  *
     836                 :            :  * This function checks that 'oh' is a valid length for its particular type of
     837                 :            :  * message, and returns an error if not. */
     838                 :            : enum ofperr
     839                 :      71729 : ofptype_decode(enum ofptype *typep, const struct ofp_header *oh)
     840                 :            : {
     841                 :            :     enum ofperr error;
     842                 :            :     enum ofpraw raw;
     843                 :            : 
     844                 :      71729 :     error = ofpraw_decode(&raw, oh);
     845         [ +  + ]:      71729 :     *typep = error ? 0 : ofptype_from_ofpraw(raw);
     846                 :      71729 :     return error;
     847                 :            : }
     848                 :            : 
     849                 :            : /* Determines the OFPTYPE_* type of the OpenFlow message in 'msg', which starts
     850                 :            :  * at 'msg->data' and has length 'msg->size' bytes.  On success,
     851                 :            :  * returns 0 and stores the type into '*typep'.  On failure, returns an
     852                 :            :  * OFPERR_* error code and zeros '*typep'.
     853                 :            :  *
     854                 :            :  * This function checks that the message has a valid length for its particular
     855                 :            :  * type of message, and returns an error if not.
     856                 :            :  *
     857                 :            :  * In addition to setting '*typep', this function pulls off the OpenFlow header
     858                 :            :  * (including the stats headers, vendor header, and any subtype header) with
     859                 :            :  * ofpbuf_pull().  It also sets 'msg->header' to the start of the OpenFlow
     860                 :            :  * header and 'msg->msg' just beyond the headers (that is, to the final value
     861                 :            :  * of msg->data). */
     862                 :            : enum ofperr
     863                 :         24 : ofptype_pull(enum ofptype *typep, struct ofpbuf *buf)
     864                 :            : {
     865                 :            :     enum ofperr error;
     866                 :            :     enum ofpraw raw;
     867                 :            : 
     868                 :         24 :     error = ofpraw_pull(&raw, buf);
     869         [ +  - ]:         24 :     *typep = error ? 0 : ofptype_from_ofpraw(raw);
     870                 :         24 :     return error;
     871                 :            : }
     872                 :            : 
     873                 :            : /* Returns the OFPTYPE_* type that corresponds to 'raw'.
     874                 :            :  *
     875                 :            :  * (This is a one-way trip, because the mapping from ofpraw to ofptype is
     876                 :            :  * many-to-one.)  */
     877                 :            : enum ofptype
     878                 :     171574 : ofptype_from_ofpraw(enum ofpraw raw)
     879                 :            : {
     880                 :     171574 :     return raw_info_get(raw)->type;
     881                 :            : }
     882                 :            : 
     883                 :            : const char *
     884                 :          1 : ofptype_get_name(enum ofptype type)
     885                 :            : {
     886         [ -  + ]:          1 :     ovs_assert(type < ARRAY_SIZE(type_names));
     887                 :          1 :     return type_names[type];
     888                 :            : }
     889                 :            : 
     890                 :            : /* Updates the 'length' field of the OpenFlow message in 'buf' to
     891                 :            :  * 'buf->size'. */
     892                 :            : void
     893                 :     154090 : ofpmsg_update_length(struct ofpbuf *buf)
     894                 :            : {
     895                 :     154090 :     struct ofp_header *oh = ofpbuf_at_assert(buf, 0, sizeof *oh);
     896                 :     154090 :     oh->length = htons(buf->size);
     897                 :     154090 : }
     898                 :            : 
     899                 :            : /* Returns just past the OpenFlow header (including the stats headers, vendor
     900                 :            :  * header, and any subtype header) in 'oh'. */
     901                 :            : const void *
     902                 :       1526 : ofpmsg_body(const struct ofp_header *oh)
     903                 :            : {
     904                 :            :     struct ofphdrs hdrs;
     905                 :            : 
     906                 :       1526 :     ofphdrs_decode_assert(&hdrs, oh, ntohs(oh->length));
     907                 :       1526 :     return (const uint8_t *) oh + ofphdrs_len(&hdrs);
     908                 :            : }
     909                 :            : 
     910                 :            : /* Return if it's a stat/multipart (OFPST) request message. */
     911                 :            : bool
     912                 :      26281 : ofpmsg_is_stat_request(const struct ofp_header *oh)
     913                 :            : {
     914                 :      26281 :     return ofp_is_stat_request(oh->version, oh->type);
     915                 :            : }
     916                 :            : 
     917                 :            : static ovs_be16 *ofpmp_flags__(const struct ofp_header *);
     918                 :            : 
     919                 :            : /* Initializes 'replies' as a new list of stats messages that reply to
     920                 :            :  * 'request', which must be a stats request message.  Initially the list will
     921                 :            :  * consist of only a single reply part without any body.  The caller should
     922                 :            :  * use calls to the other ofpmp_*() functions to add to the body and split the
     923                 :            :  * message into multiple parts, if necessary. */
     924                 :            : void
     925                 :        556 : ofpmp_init(struct ovs_list *replies, const struct ofp_header *request)
     926                 :            : {
     927                 :            :     struct ofpbuf *msg;
     928                 :            : 
     929                 :        556 :     ovs_list_init(replies);
     930                 :            : 
     931                 :        556 :     msg = ofpraw_alloc_stats_reply(request, 1000);
     932                 :        556 :     ovs_list_push_back(replies, &msg->list_node);
     933                 :        556 : }
     934                 :            : 
     935                 :            : /* Prepares to append up to 'len' bytes to the series of statistics replies in
     936                 :            :  * 'replies', which should have been initialized with ofpmp_init(), if
     937                 :            :  * necessary adding a new reply to the list.
     938                 :            :  *
     939                 :            :  * Returns an ofpbuf with at least 'len' bytes of tailroom.  The 'len' bytes
     940                 :            :  * have not actually been allocated, so the caller must do so with
     941                 :            :  * e.g. ofpbuf_put_uninit(). */
     942                 :            : struct ofpbuf *
     943                 :        119 : ofpmp_reserve(struct ovs_list *replies, size_t len)
     944                 :            : {
     945                 :        119 :     struct ofpbuf *msg = ofpbuf_from_list(ovs_list_back(replies));
     946                 :            : 
     947         [ +  + ]:        119 :     if (msg->size + len <= UINT16_MAX) {
     948                 :         79 :         ofpbuf_prealloc_tailroom(msg, len);
     949                 :         79 :         return msg;
     950                 :            :     } else {
     951                 :            :         unsigned int hdrs_len;
     952                 :            :         struct ofpbuf *next;
     953                 :            :         struct ofphdrs hdrs;
     954                 :            : 
     955                 :         40 :         ofphdrs_decode_assert(&hdrs, msg->data, msg->size);
     956                 :         40 :         hdrs_len = ofphdrs_len(&hdrs);
     957                 :            : 
     958                 :         40 :         next = ofpbuf_new(MAX(1024, hdrs_len + len));
     959                 :         40 :         ofpbuf_put(next, msg->data, hdrs_len);
     960                 :         40 :         next->header = next->data;
     961                 :         40 :         next->msg = ofpbuf_tail(next);
     962                 :         40 :         ovs_list_push_back(replies, &next->list_node);
     963                 :            : 
     964                 :         40 :         *ofpmp_flags__(msg->data) |= htons(OFPSF_REPLY_MORE);
     965                 :            : 
     966                 :         40 :         return next;
     967                 :            :     }
     968                 :            : }
     969                 :            : 
     970                 :            : /* Appends 'len' bytes to the series of statistics replies in 'replies', and
     971                 :            :  * returns the first byte. */
     972                 :            : void *
     973                 :        118 : ofpmp_append(struct ovs_list *replies, size_t len)
     974                 :            : {
     975                 :        118 :     return ofpbuf_put_uninit(ofpmp_reserve(replies, len), len);
     976                 :            : }
     977                 :            : 
     978                 :            : /* Sometimes, when composing stats replies, it's difficult to predict how long
     979                 :            :  * an individual reply chunk will be before actually encoding it into the reply
     980                 :            :  * buffer.  This function allows easy handling of this case: just encode the
     981                 :            :  * reply, then use this function to break the message into two pieces if it
     982                 :            :  * exceeds the OpenFlow message limit.
     983                 :            :  *
     984                 :            :  * In detail, if the final stats message in 'replies' is too long for OpenFlow,
     985                 :            :  * this function breaks it into two separate stats replies, the first one with
     986                 :            :  * the first 'start_ofs' bytes, the second one containing the bytes from that
     987                 :            :  * offset onward. */
     988                 :            : void
     989                 :      27112 : ofpmp_postappend(struct ovs_list *replies, size_t start_ofs)
     990                 :            : {
     991                 :      27112 :     struct ofpbuf *msg = ofpbuf_from_list(ovs_list_back(replies));
     992                 :            : 
     993         [ -  + ]:      27112 :     ovs_assert(start_ofs <= UINT16_MAX);
     994         [ +  + ]:      27112 :     if (msg->size > UINT16_MAX) {
     995                 :         40 :         size_t len = msg->size - start_ofs;
     996                 :         40 :         memcpy(ofpmp_append(replies, len),
     997                 :         40 :                (const uint8_t *) msg->data + start_ofs, len);
     998                 :         40 :         msg->size = start_ofs;
     999                 :            :     }
    1000                 :      27112 : }
    1001                 :            : 
    1002                 :            : /* Returns the OpenFlow version of the replies being constructed in 'replies',
    1003                 :            :  * which should have been initialized by ofpmp_init(). */
    1004                 :            : enum ofp_version
    1005                 :      24657 : ofpmp_version(struct ovs_list *replies)
    1006                 :            : {
    1007                 :      24657 :     struct ofpbuf *msg = ofpbuf_from_list(ovs_list_back(replies));
    1008                 :      24657 :     const struct ofp_header *oh = msg->data;
    1009                 :            : 
    1010                 :      24657 :     return oh->version;
    1011                 :            : }
    1012                 :            : 
    1013                 :            : /* Determines the OFPRAW_* type of the OpenFlow messages in 'replies', which
    1014                 :            :  * should have been initialized by ofpmp_init(). */
    1015                 :            : enum ofpraw
    1016                 :      18639 : ofpmp_decode_raw(struct ovs_list *replies)
    1017                 :            : {
    1018                 :      18639 :     struct ofpbuf *msg = ofpbuf_from_list(ovs_list_back(replies));
    1019                 :            :     enum ofperr error;
    1020                 :            :     enum ofpraw raw;
    1021                 :            : 
    1022                 :      18639 :     error = ofpraw_decode_partial(&raw, msg->data, msg->size);
    1023         [ -  + ]:      18639 :     ovs_assert(!error);
    1024                 :      18639 :     return raw;
    1025                 :            : }
    1026                 :            : 
    1027                 :            : static ovs_be16 *
    1028                 :       2386 : ofpmp_flags__(const struct ofp_header *oh)
    1029                 :            : {
    1030      [ +  +  - ]:       2386 :     switch ((enum ofp_version)oh->version) {
    1031                 :            :     case OFP10_VERSION:
    1032                 :       1244 :         return &((struct ofp10_stats_msg *) oh)->flags;
    1033                 :            :     case OFP11_VERSION:
    1034                 :            :     case OFP12_VERSION:
    1035                 :            :     case OFP13_VERSION:
    1036                 :            :     case OFP14_VERSION:
    1037                 :            :     case OFP15_VERSION:
    1038                 :            :     case OFP16_VERSION:
    1039                 :       1142 :         return &((struct ofp11_stats_msg *) oh)->flags;
    1040                 :            :     default:
    1041                 :          0 :         OVS_NOT_REACHED();
    1042                 :            :     }
    1043                 :            : }
    1044                 :            : 
    1045                 :            : /* Returns the OFPSF_* flags found in the OpenFlow stats header of 'oh', which
    1046                 :            :  * must be an OpenFlow stats request or reply.
    1047                 :            :  *
    1048                 :            :  * (OFPSF_REPLY_MORE is the only defined flag.) */
    1049                 :            : uint16_t
    1050                 :       2346 : ofpmp_flags(const struct ofp_header *oh)
    1051                 :            : {
    1052                 :       2346 :     return ntohs(*ofpmp_flags__(oh));
    1053                 :            : }
    1054                 :            : 
    1055                 :            : /* Returns true if the OFPSF_REPLY_MORE flag is set in the OpenFlow stats
    1056                 :            :  * header of 'oh', which must be an OpenFlow stats request or reply, false if
    1057                 :            :  * it is not set. */
    1058                 :            : bool
    1059                 :        757 : ofpmp_more(const struct ofp_header *oh)
    1060                 :            : {
    1061                 :        757 :     return (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0;
    1062                 :            : }
    1063                 :            : 
    1064                 :            : static void ofpmsgs_init(void);
    1065                 :            : 
    1066                 :            : static const struct raw_info *
    1067                 :     700459 : raw_info_get(enum ofpraw raw)
    1068                 :            : {
    1069                 :     700459 :     ofpmsgs_init();
    1070                 :            : 
    1071         [ -  + ]:     700459 :     ovs_assert(raw < ARRAY_SIZE(raw_infos));
    1072                 :     700459 :     return &raw_infos[raw];
    1073                 :            : }
    1074                 :            : 
    1075                 :            : static struct raw_instance *
    1076                 :     428137 : raw_instance_get(const struct raw_info *info, uint8_t version)
    1077                 :            : {
    1078 [ +  - ][ -  + ]:     428137 :     ovs_assert(version >= info->min_version && version <= info->max_version);
    1079                 :     428137 :     return &info->instances[version - info->min_version];
    1080                 :            : }
    1081                 :            : 
    1082                 :            : static enum ofperr
    1083                 :     367526 : ofpraw_from_ofphdrs(enum ofpraw *raw, const struct ofphdrs *hdrs)
    1084                 :            : {
    1085                 :            :     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
    1086                 :            : 
    1087                 :            :     struct raw_instance *raw_hdrs;
    1088                 :            :     uint32_t hash;
    1089                 :            : 
    1090                 :     367526 :     ofpmsgs_init();
    1091                 :            : 
    1092                 :     367526 :     hash = ofphdrs_hash(hdrs);
    1093 [ +  + ][ -  + ]:     367526 :     HMAP_FOR_EACH_WITH_HASH (raw_hdrs, hmap_node, hash, &raw_instance_map) {
    1094         [ +  - ]:     367516 :         if (ofphdrs_equal(hdrs, &raw_hdrs->hdrs)) {
    1095                 :     367516 :             *raw = raw_hdrs->raw;
    1096                 :     367516 :             return 0;
    1097                 :            :         }
    1098                 :            :     }
    1099                 :            : 
    1100         [ +  + ]:         10 :     if (!VLOG_DROP_WARN(&rl)) {
    1101                 :            :         struct ds s;
    1102                 :            : 
    1103                 :          4 :         ds_init(&s);
    1104                 :          4 :         ds_put_format(&s, "version %"PRIu8", type %"PRIu8,
    1105                 :          8 :                       hdrs->version, hdrs->type);
    1106         [ -  + ]:          4 :         if (ofphdrs_is_stat(hdrs)) {
    1107                 :          0 :             ds_put_format(&s, ", stat %"PRIu16, hdrs->stat);
    1108                 :            :         }
    1109         [ -  + ]:          4 :         if (hdrs->vendor) {
    1110                 :          0 :             ds_put_format(&s, ", vendor 0x%"PRIx32", subtype %"PRIu32,
    1111                 :            :                           hdrs->vendor, hdrs->subtype);
    1112                 :            :         }
    1113         [ +  - ]:          4 :         VLOG_WARN("unknown OpenFlow message (%s)", ds_cstr(&s));
    1114                 :          4 :         ds_destroy(&s);
    1115                 :            :     }
    1116                 :            : 
    1117   [ +  -  -  + ]:         20 :     return (hdrs->vendor ? OFPERR_OFPBRC_BAD_SUBTYPE
    1118                 :         10 :             : ofphdrs_is_stat(hdrs) ? OFPERR_OFPBRC_BAD_STAT
    1119                 :            :             : OFPERR_OFPBRC_BAD_TYPE);
    1120                 :            : }
    1121                 :            : 
    1122                 :            : static void
    1123                 :    1067985 : ofpmsgs_init(void)
    1124                 :            : {
    1125                 :            :     static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
    1126                 :            :     const struct raw_info *info;
    1127                 :            : 
    1128         [ +  + ]:    1067985 :     if (!ovsthread_once_start(&once)) {
    1129                 :    1063701 :         return;
    1130                 :            :     }
    1131                 :            : 
    1132                 :       4284 :     hmap_init(&raw_instance_map);
    1133         [ +  + ]:     599760 :     for (info = raw_infos; info < &raw_infos[ARRAY_SIZE(raw_infos)]; info++)
    1134                 :            :     {
    1135                 :     595476 :         int n_instances = info->max_version - info->min_version + 1;
    1136                 :            :         struct raw_instance *inst;
    1137                 :            : 
    1138         [ +  + ]:    7111440 :         for (inst = info->instances;
    1139                 :    7111440 :              inst < &info->instances[n_instances];
    1140                 :    6515964 :              inst++) {
    1141                 :    6515964 :             inst->hdrs_len = ofphdrs_len(&inst->hdrs);
    1142                 :    6515964 :             hmap_insert(&raw_instance_map, &inst->hmap_node,
    1143                 :            :                         ofphdrs_hash(&inst->hdrs));
    1144                 :            :         }
    1145                 :            :     }
    1146                 :            : 
    1147                 :       4284 :     ovsthread_once_done(&once);
    1148                 :            : }

Generated by: LCOV version 1.12