LCOV - code coverage report
Current view: top level - lib - netlink.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 215 295 72.9 %
Date: 2016-09-14 01:02:56 Functions: 49 66 74.2 %
Branches: 69 118 58.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 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 "netlink.h"
      19                 :            : #include <errno.h>
      20                 :            : #include <inttypes.h>
      21                 :            : #include <sys/types.h>
      22                 :            : #include <unistd.h>
      23                 :            : #include "coverage.h"
      24                 :            : #include "flow.h"
      25                 :            : #include "netlink-protocol.h"
      26                 :            : #include "openvswitch/ofpbuf.h"
      27                 :            : #include "timeval.h"
      28                 :            : #include "unaligned.h"
      29                 :            : #include "openvswitch/vlog.h"
      30                 :            : #include "util.h"
      31                 :            : 
      32                 :      20190 : VLOG_DEFINE_THIS_MODULE(netlink);
      33                 :            : 
      34                 :            : /* A single (bad) Netlink message can in theory dump out many, many log
      35                 :            :  * messages, so the burst size is set quite high here to avoid missing useful
      36                 :            :  * information.  Also, at high logging levels we log *all* Netlink messages. */
      37                 :            : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 600);
      38                 :            : 
      39                 :            : /* Returns the nlmsghdr at the head of 'msg'.
      40                 :            :  *
      41                 :            :  * 'msg' must be at least as large as a nlmsghdr. */
      42                 :            : struct nlmsghdr *
      43                 :     155385 : nl_msg_nlmsghdr(const struct ofpbuf *msg)
      44                 :            : {
      45                 :     155385 :     return ofpbuf_at_assert(msg, 0, NLMSG_HDRLEN);
      46                 :            : }
      47                 :            : 
      48                 :            : /* Returns the genlmsghdr just past 'msg''s nlmsghdr.
      49                 :            :  *
      50                 :            :  * Returns a null pointer if 'msg' is not large enough to contain an nlmsghdr
      51                 :            :  * and a genlmsghdr. */
      52                 :            : struct genlmsghdr *
      53                 :          0 : nl_msg_genlmsghdr(const struct ofpbuf *msg)
      54                 :            : {
      55                 :          0 :     return ofpbuf_at(msg, NLMSG_HDRLEN, GENL_HDRLEN);
      56                 :            : }
      57                 :            : 
      58                 :            : /* If 'buffer' is a NLMSG_ERROR message, stores 0 in '*errorp' if it is an ACK
      59                 :            :  * message, otherwise a positive errno value, and returns true.  If 'buffer' is
      60                 :            :  * not an NLMSG_ERROR message, returns false.
      61                 :            :  *
      62                 :            :  * 'msg' must be at least as large as a nlmsghdr. */
      63                 :            : bool
      64                 :      22724 : nl_msg_nlmsgerr(const struct ofpbuf *msg, int *errorp)
      65                 :            : {
      66         [ +  + ]:      22724 :     if (nl_msg_nlmsghdr(msg)->nlmsg_type == NLMSG_ERROR) {
      67                 :       1523 :         struct nlmsgerr *err = ofpbuf_at(msg, NLMSG_HDRLEN, sizeof *err);
      68                 :       1523 :         int code = EPROTO;
      69         [ -  + ]:       1523 :         if (!err) {
      70         [ #  # ]:          0 :             VLOG_ERR_RL(&rl, "received invalid nlmsgerr (%"PRIu32" bytes < %"PRIuSIZE")",
      71                 :            :                         msg->size, NLMSG_HDRLEN + sizeof *err);
      72 [ +  - ][ +  - ]:       1523 :         } else if (err->error <= 0 && err->error > INT_MIN) {
      73                 :       1523 :             code = -err->error;
      74                 :            :         }
      75         [ +  - ]:       1523 :         if (errorp) {
      76                 :       1523 :             *errorp = code;
      77                 :            :         }
      78                 :       1523 :         return true;
      79                 :            :     } else {
      80                 :      21201 :         return false;
      81                 :            :     }
      82                 :            : }
      83                 :            : 
      84                 :            : /* Ensures that 'b' has room for at least 'size' bytes plus netlink padding at
      85                 :            :  * its tail end, reallocating and copying its data if necessary. */
      86                 :            : void
      87                 :      19829 : nl_msg_reserve(struct ofpbuf *msg, size_t size)
      88                 :            : {
      89                 :      19829 :     ofpbuf_prealloc_tailroom(msg, NLMSG_ALIGN(size));
      90                 :      19829 : }
      91                 :            : 
      92                 :            : /* Puts a nlmsghdr at the beginning of 'msg', which must be initially empty.
      93                 :            :  * Uses the given 'type' and 'flags'.  'expected_payload' should be
      94                 :            :  * an estimate of the number of payload bytes to be supplied; if the size of
      95                 :            :  * the payload is unknown a value of 0 is acceptable.
      96                 :            :  *
      97                 :            :  * 'type' is ordinarily an enumerated value specific to the Netlink protocol
      98                 :            :  * (e.g. RTM_NEWLINK, for NETLINK_ROUTE protocol).  For Generic Netlink, 'type'
      99                 :            :  * is the family number obtained via nl_lookup_genl_family().
     100                 :            :  *
     101                 :            :  * 'flags' is a bit-mask that indicates what kind of request is being made.  It
     102                 :            :  * is often NLM_F_REQUEST indicating that a request is being made, commonly
     103                 :            :  * or'd with NLM_F_ACK to request an acknowledgement.
     104                 :            :  *
     105                 :            :  * Sets the new nlmsghdr's nlmsg_len, nlmsg_seq, and nlmsg_pid fields to 0 for
     106                 :            :  * now.  Functions that send Netlink messages will fill these in just before
     107                 :            :  * sending the message.
     108                 :            :  *
     109                 :            :  * nl_msg_put_genlmsghdr() is more convenient for composing a Generic Netlink
     110                 :            :  * message. */
     111                 :            : void
     112                 :      19829 : nl_msg_put_nlmsghdr(struct ofpbuf *msg,
     113                 :            :                     size_t expected_payload, uint32_t type, uint32_t flags)
     114                 :            : {
     115                 :            :     struct nlmsghdr *nlmsghdr;
     116                 :            : 
     117         [ -  + ]:      19829 :     ovs_assert(msg->size == 0);
     118                 :            : 
     119                 :      19829 :     nl_msg_reserve(msg, NLMSG_HDRLEN + expected_payload);
     120                 :      19829 :     nlmsghdr = nl_msg_put_uninit(msg, NLMSG_HDRLEN);
     121                 :      19829 :     nlmsghdr->nlmsg_len = 0;
     122                 :      19829 :     nlmsghdr->nlmsg_type = type;
     123                 :      19829 :     nlmsghdr->nlmsg_flags = flags;
     124                 :      19829 :     nlmsghdr->nlmsg_seq = 0;
     125                 :      19829 :     nlmsghdr->nlmsg_pid = 0;
     126                 :      19829 : }
     127                 :            : 
     128                 :            : /* Puts a nlmsghdr and genlmsghdr at the beginning of 'msg', which must be
     129                 :            :  * initially empty.  'expected_payload' should be an estimate of the number of
     130                 :            :  * payload bytes to be supplied; if the size of the payload is unknown a value
     131                 :            :  * of 0 is acceptable.
     132                 :            :  *
     133                 :            :  * 'family' is the family number obtained via nl_lookup_genl_family().
     134                 :            :  *
     135                 :            :  * 'flags' is a bit-mask that indicates what kind of request is being made.  It
     136                 :            :  * is often NLM_F_REQUEST indicating that a request is being made, commonly
     137                 :            :  * or'd with NLM_F_ACK to request an acknowledgement.
     138                 :            :  *
     139                 :            :  * 'cmd' is an enumerated value specific to the Generic Netlink family
     140                 :            :  * (e.g. CTRL_CMD_NEWFAMILY for the GENL_ID_CTRL family).
     141                 :            :  *
     142                 :            :  * 'version' is a version number specific to the family and command (often 1).
     143                 :            :  *
     144                 :            :  * Sets the new nlmsghdr's nlmsg_pid field to 0 for now.  nl_sock_send() will
     145                 :            :  * fill it in just before sending the message.
     146                 :            :  *
     147                 :            :  * nl_msg_put_nlmsghdr() should be used to compose Netlink messages that are
     148                 :            :  * not Generic Netlink messages. */
     149                 :            : void
     150                 :      15304 : nl_msg_put_genlmsghdr(struct ofpbuf *msg, size_t expected_payload,
     151                 :            :                       int family, uint32_t flags, uint8_t cmd, uint8_t version)
     152                 :            : {
     153                 :            :     struct genlmsghdr *genlmsghdr;
     154                 :            : 
     155                 :      15304 :     nl_msg_put_nlmsghdr(msg, GENL_HDRLEN + expected_payload, family, flags);
     156         [ -  + ]:      15304 :     ovs_assert(msg->size == NLMSG_HDRLEN);
     157                 :      15304 :     genlmsghdr = nl_msg_put_uninit(msg, GENL_HDRLEN);
     158                 :      15304 :     genlmsghdr->cmd = cmd;
     159                 :      15304 :     genlmsghdr->version = version;
     160                 :      15304 :     genlmsghdr->reserved = 0;
     161                 :      15304 : }
     162                 :            : 
     163                 :            : /* Appends the 'size' bytes of data in 'p', plus Netlink padding if needed, to
     164                 :            :  * the tail end of 'msg'.  Data in 'msg' is reallocated and copied if
     165                 :            :  * necessary. */
     166                 :            : void
     167                 :        801 : nl_msg_put(struct ofpbuf *msg, const void *data, size_t size)
     168                 :            : {
     169                 :        801 :     memcpy(nl_msg_put_uninit(msg, size), data, size);
     170                 :        801 : }
     171                 :            : 
     172                 :            : /* Appends 'size' bytes of data, plus Netlink padding if needed, to the tail
     173                 :            :  * end of 'msg', reallocating and copying its data if necessary.  Returns a
     174                 :            :  * pointer to the first byte of the new data, which is left uninitialized. */
     175                 :            : void *
     176                 :     683702 : nl_msg_put_uninit(struct ofpbuf *msg, size_t size)
     177                 :            : {
     178                 :     683702 :     size_t pad = PAD_SIZE(size, NLMSG_ALIGNTO);
     179                 :     683702 :     char *p = ofpbuf_put_uninit(msg, size + pad);
     180         [ +  + ]:     683702 :     if (pad) {
     181                 :      92189 :         memset(p + size, 0, pad);
     182                 :            :     }
     183                 :     683702 :     return p;
     184                 :            : }
     185                 :            : 
     186                 :            : /* Prepends the 'size' bytes of data in 'p', plus Netlink padding if needed, to
     187                 :            :  * the head end of 'msg'.  Data in 'msg' is reallocated and copied if
     188                 :            :  * necessary. */
     189                 :            : void
     190                 :          0 : nl_msg_push(struct ofpbuf *msg, const void *data, size_t size)
     191                 :            : {
     192                 :          0 :     memcpy(nl_msg_push_uninit(msg, size), data, size);
     193                 :          0 : }
     194                 :            : 
     195                 :            : /* Prepends 'size' bytes of data, plus Netlink padding if needed, to the head
     196                 :            :  * end of 'msg', reallocating and copying its data if necessary.  Returns a
     197                 :            :  * pointer to the first byte of the new data, which is left uninitialized. */
     198                 :            : void *
     199                 :          0 : nl_msg_push_uninit(struct ofpbuf *msg, size_t size)
     200                 :            : {
     201                 :          0 :     size_t pad = PAD_SIZE(size, NLMSG_ALIGNTO);
     202                 :          0 :     char *p = ofpbuf_push_uninit(msg, size + pad);
     203         [ #  # ]:          0 :     if (pad) {
     204                 :          0 :         memset(p + size, 0, pad);
     205                 :            :     }
     206                 :          0 :     return p;
     207                 :            : }
     208                 :            : 
     209                 :            : /* Appends a Netlink attribute of the given 'type' and room for 'size' bytes of
     210                 :            :  * data as its payload, plus Netlink padding if needed, to the tail end of
     211                 :            :  * 'msg', reallocating and copying its data if necessary.  Returns a pointer to
     212                 :            :  * the first byte of data in the attribute, which is left uninitialized. */
     213                 :            : void *
     214                 :     647655 : nl_msg_put_unspec_uninit(struct ofpbuf *msg, uint16_t type, size_t size)
     215                 :            : {
     216                 :     647655 :     size_t total_size = NLA_HDRLEN + size;
     217                 :     647655 :     struct nlattr* nla = nl_msg_put_uninit(msg, total_size);
     218         [ -  + ]:     647655 :     ovs_assert(!nl_attr_oversized(size));
     219                 :     647655 :     nla->nla_len = total_size;
     220                 :     647655 :     nla->nla_type = type;
     221                 :     647655 :     return nla + 1;
     222                 :            : }
     223                 :            : 
     224                 :            : /* Appends a Netlink attribute of the given 'type' and room for 'size' bytes of
     225                 :            :  * data as its payload, plus Netlink padding if needed, to the tail end of
     226                 :            :  * 'msg', reallocating and copying its data if necessary.  Returns a pointer to
     227                 :            :  * the first byte of data in the attribute, which is zeroed. */
     228                 :            : void *
     229                 :      28446 : nl_msg_put_unspec_zero(struct ofpbuf *msg, uint16_t type, size_t size)
     230                 :            : {
     231                 :      28446 :     void *data = nl_msg_put_unspec_uninit(msg, type, size);
     232                 :      28446 :     memset(data, 0, size);
     233                 :      28446 :     return data;
     234                 :            : }
     235                 :            : 
     236                 :            : /* Appends a Netlink attribute of the given 'type' and the 'size' bytes of
     237                 :            :  * 'data' as its payload, to the tail end of 'msg', reallocating and copying
     238                 :            :  * its data if necessary.  Returns a pointer to the first byte of data in the
     239                 :            :  * attribute, which is left uninitialized. */
     240                 :            : void
     241                 :     548495 : nl_msg_put_unspec(struct ofpbuf *msg, uint16_t type,
     242                 :            :                   const void *data, size_t size)
     243                 :            : {
     244                 :     548495 :     memcpy(nl_msg_put_unspec_uninit(msg, type, size), data, size);
     245                 :     548495 : }
     246                 :            : 
     247                 :            : /* Appends a Netlink attribute of the given 'type' and no payload to 'msg'.
     248                 :            :  * (Some Netlink protocols use the presence or absence of an attribute as a
     249                 :            :  * Boolean flag.) */
     250                 :            : void
     251                 :       5245 : nl_msg_put_flag(struct ofpbuf *msg, uint16_t type)
     252                 :            : {
     253                 :       5245 :     nl_msg_put_unspec(msg, type, NULL, 0);
     254                 :       5245 : }
     255                 :            : 
     256                 :            : /* Appends a Netlink attribute of the given 'type' and the given 8-bit 'value'
     257                 :            :  * to 'msg'. */
     258                 :            : void
     259                 :      15097 : nl_msg_put_u8(struct ofpbuf *msg, uint16_t type, uint8_t value)
     260                 :            : {
     261                 :      15097 :     nl_msg_put_unspec(msg, type, &value, sizeof value);
     262                 :      15097 : }
     263                 :            : 
     264                 :            : /* Appends a Netlink attribute of the given 'type' and the given 16-bit host
     265                 :            :  * byte order 'value' to 'msg'. */
     266                 :            : void
     267                 :      28219 : nl_msg_put_u16(struct ofpbuf *msg, uint16_t type, uint16_t value)
     268                 :            : {
     269                 :      28219 :     nl_msg_put_unspec(msg, type, &value, sizeof value);
     270                 :      28219 : }
     271                 :            : 
     272                 :            : /* Appends a Netlink attribute of the given 'type' and the given 32-bit host
     273                 :            :  * byte order 'value' to 'msg'. */
     274                 :            : void
     275                 :     329974 : nl_msg_put_u32(struct ofpbuf *msg, uint16_t type, uint32_t value)
     276                 :            : {
     277                 :     329974 :     nl_msg_put_unspec(msg, type, &value, sizeof value);
     278                 :     329974 : }
     279                 :            : 
     280                 :            : /* Appends a Netlink attribute of the given 'type' and the given 64-bit host
     281                 :            :  * byte order 'value' to 'msg'. */
     282                 :            : void
     283                 :          0 : nl_msg_put_u64(struct ofpbuf *msg, uint16_t type, uint64_t value)
     284                 :            : {
     285                 :          0 :     nl_msg_put_unspec(msg, type, &value, sizeof value);
     286                 :          0 : }
     287                 :            : 
     288                 :            : /* Appends a Netlink attribute of the given 'type' and the given 16-bit network
     289                 :            :  * byte order 'value' to 'msg'. */
     290                 :            : void
     291                 :      31967 : nl_msg_put_be16(struct ofpbuf *msg, uint16_t type, ovs_be16 value)
     292                 :            : {
     293                 :      31967 :     nl_msg_put_unspec(msg, type, &value, sizeof value);
     294                 :      31967 : }
     295                 :            : 
     296                 :            : /* Appends a Netlink attribute of the given 'type' and the given 32-bit network
     297                 :            :  * byte order 'value' to 'msg'. */
     298                 :            : void
     299                 :       4035 : nl_msg_put_be32(struct ofpbuf *msg, uint16_t type, ovs_be32 value)
     300                 :            : {
     301                 :       4035 :     nl_msg_put_unspec(msg, type, &value, sizeof value);
     302                 :       4035 : }
     303                 :            : 
     304                 :            : /* Appends a Netlink attribute of the given 'type' and the given 64-bit network
     305                 :            :  * byte order 'value' to 'msg'. */
     306                 :            : void
     307                 :       2873 : nl_msg_put_be64(struct ofpbuf *msg, uint16_t type, ovs_be64 value)
     308                 :            : {
     309                 :       2873 :     nl_msg_put_unspec(msg, type, &value, sizeof value);
     310                 :       2873 : }
     311                 :            : 
     312                 :            : /* Appends a Netlink attribute of the given 'type' and the given IPv6
     313                 :            :  * address order 'value' to 'msg'. */
     314                 :            : void
     315                 :         13 : nl_msg_put_in6_addr(struct ofpbuf *msg, uint16_t type,
     316                 :            :                     const struct in6_addr *value)
     317                 :            : {
     318                 :         13 :     nl_msg_put_unspec(msg, type, value, sizeof *value);
     319                 :         13 : }
     320                 :            : 
     321                 :            : /* Appends a Netlink attribute of the given 'type' and the given odp_port_t
     322                 :            :  * 'value' to 'msg'. */
     323                 :            : void
     324                 :     121086 : nl_msg_put_odp_port(struct ofpbuf *msg, uint16_t type, odp_port_t value)
     325                 :            : {
     326                 :     121086 :     nl_msg_put_u32(msg, type, odp_to_u32(value));
     327                 :     121086 : }
     328                 :            : 
     329                 :            : /* Appends a Netlink attribute of the given 'type' with the 'len' characters
     330                 :            :  * of 'value', followed by the null byte to 'msg'. */
     331                 :            : void
     332                 :          2 : nl_msg_put_string__(struct ofpbuf *msg, uint16_t type, const char *value,
     333                 :            :                     size_t len)
     334                 :            : {
     335                 :          2 :     char *data = nl_msg_put_unspec_uninit(msg, type, len + 1);
     336                 :            : 
     337                 :          2 :     memcpy(data, value, len);
     338                 :          2 :     data[len] = '\0';
     339                 :          2 : }
     340                 :            : 
     341                 :            : /* Appends a Netlink attribute of the given 'type' and the given
     342                 :            :  * null-terminated string 'value' to 'msg'. */
     343                 :            : void
     344                 :       6876 : nl_msg_put_string(struct ofpbuf *msg, uint16_t type, const char *value)
     345                 :            : {
     346                 :       6876 :     nl_msg_put_unspec(msg, type, value, strlen(value) + 1);
     347                 :       6876 : }
     348                 :            : 
     349                 :            : /* Prepends a Netlink attribute of the given 'type' and room for 'size' bytes
     350                 :            :  * of data as its payload, plus Netlink padding if needed, to the head end of
     351                 :            :  * 'msg', reallocating and copying its data if necessary.  Returns a pointer to
     352                 :            :  * the first byte of data in the attribute, which is left uninitialized. */
     353                 :            : void *
     354                 :          0 : nl_msg_push_unspec_uninit(struct ofpbuf *msg, uint16_t type, size_t size)
     355                 :            : {
     356                 :          0 :     size_t total_size = NLA_HDRLEN + size;
     357                 :          0 :     struct nlattr* nla = nl_msg_push_uninit(msg, total_size);
     358         [ #  # ]:          0 :     ovs_assert(!nl_attr_oversized(size));
     359                 :          0 :     nla->nla_len = total_size;
     360                 :          0 :     nla->nla_type = type;
     361                 :          0 :     return nla + 1;
     362                 :            : }
     363                 :            : 
     364                 :            : /* Prepends a Netlink attribute of the given 'type' and the 'size' bytes of
     365                 :            :  * 'data' as its payload, to the head end of 'msg', reallocating and copying
     366                 :            :  * its data if necessary.  Returns a pointer to the first byte of data in the
     367                 :            :  * attribute, which is left uninitialized. */
     368                 :            : void
     369                 :          0 : nl_msg_push_unspec(struct ofpbuf *msg, uint16_t type,
     370                 :            :                   const void *data, size_t size)
     371                 :            : {
     372                 :          0 :     memcpy(nl_msg_push_unspec_uninit(msg, type, size), data, size);
     373                 :          0 : }
     374                 :            : 
     375                 :            : /* Prepends a Netlink attribute of the given 'type' and no payload to 'msg'.
     376                 :            :  * (Some Netlink protocols use the presence or absence of an attribute as a
     377                 :            :  * Boolean flag.) */
     378                 :            : void
     379                 :          0 : nl_msg_push_flag(struct ofpbuf *msg, uint16_t type)
     380                 :            : {
     381                 :          0 :     nl_msg_push_unspec_uninit(msg, type, 0);
     382                 :          0 : }
     383                 :            : 
     384                 :            : /* Prepends a Netlink attribute of the given 'type' and the given 8-bit 'value'
     385                 :            :  * to 'msg'. */
     386                 :            : void
     387                 :          0 : nl_msg_push_u8(struct ofpbuf *msg, uint16_t type, uint8_t value)
     388                 :            : {
     389                 :          0 :     nl_msg_push_unspec(msg, type, &value, sizeof value);
     390                 :          0 : }
     391                 :            : 
     392                 :            : /* Prepends a Netlink attribute of the given 'type' and the given 16-bit host
     393                 :            :  * byte order 'value' to 'msg'. */
     394                 :            : void
     395                 :          0 : nl_msg_push_u16(struct ofpbuf *msg, uint16_t type, uint16_t value)
     396                 :            : {
     397                 :          0 :     nl_msg_push_unspec(msg, type, &value, sizeof value);
     398                 :          0 : }
     399                 :            : 
     400                 :            : /* Prepends a Netlink attribute of the given 'type' and the given 32-bit host
     401                 :            :  * byte order 'value' to 'msg'. */
     402                 :            : void
     403                 :          0 : nl_msg_push_u32(struct ofpbuf *msg, uint16_t type, uint32_t value)
     404                 :            : {
     405                 :          0 :     nl_msg_push_unspec(msg, type, &value, sizeof value);
     406                 :          0 : }
     407                 :            : 
     408                 :            : /* Prepends a Netlink attribute of the given 'type' and the given 64-bit host
     409                 :            :  * byte order 'value' to 'msg'. */
     410                 :            : void
     411                 :          0 : nl_msg_push_u64(struct ofpbuf *msg, uint16_t type, uint64_t value)
     412                 :            : {
     413                 :          0 :     nl_msg_push_unspec(msg, type, &value, sizeof value);
     414                 :          0 : }
     415                 :            : 
     416                 :            : /* Prepends a Netlink attribute of the given 'type' and the given 16-bit
     417                 :            :  * network byte order 'value' to 'msg'. */
     418                 :            : void
     419                 :          0 : nl_msg_push_be16(struct ofpbuf *msg, uint16_t type, ovs_be16 value)
     420                 :            : {
     421                 :          0 :     nl_msg_push_unspec(msg, type, &value, sizeof value);
     422                 :          0 : }
     423                 :            : 
     424                 :            : /* Prepends a Netlink attribute of the given 'type' and the given 32-bit
     425                 :            :  * network byte order 'value' to 'msg'. */
     426                 :            : void
     427                 :          0 : nl_msg_push_be32(struct ofpbuf *msg, uint16_t type, ovs_be32 value)
     428                 :            : {
     429                 :          0 :     nl_msg_push_unspec(msg, type, &value, sizeof value);
     430                 :          0 : }
     431                 :            : 
     432                 :            : /* Prepends a Netlink attribute of the given 'type' and the given 64-bit
     433                 :            :  * network byte order 'value' to 'msg'. */
     434                 :            : void
     435                 :          0 : nl_msg_push_be64(struct ofpbuf *msg, uint16_t type, ovs_be64 value)
     436                 :            : {
     437                 :          0 :     nl_msg_push_unspec(msg, type, &value, sizeof value);
     438                 :          0 : }
     439                 :            : 
     440                 :            : /* Prepends a Netlink attribute of the given 'type' and the given
     441                 :            :  * null-terminated string 'value' to 'msg'. */
     442                 :            : void
     443                 :          0 : nl_msg_push_string(struct ofpbuf *msg, uint16_t type, const char *value)
     444                 :            : {
     445                 :          0 :     nl_msg_push_unspec(msg, type, value, strlen(value) + 1);
     446                 :          0 : }
     447                 :            : 
     448                 :            : /* Adds the header for nested Netlink attributes to 'msg', with the specified
     449                 :            :  * 'type', and returns the header's offset within 'msg'.  The caller should add
     450                 :            :  * the content for the nested Netlink attribute to 'msg' (e.g. using the other
     451                 :            :  * nl_msg_*() functions), and then pass the returned offset to
     452                 :            :  * nl_msg_end_nested() to finish up the nested attributes. */
     453                 :            : size_t
     454                 :      58243 : nl_msg_start_nested(struct ofpbuf *msg, uint16_t type)
     455                 :            : {
     456                 :      58243 :     size_t offset = msg->size;
     457                 :      58243 :     nl_msg_put_unspec(msg, type, NULL, 0);
     458                 :      58243 :     return offset;
     459                 :            : }
     460                 :            : 
     461                 :            : /* Finalizes a nested Netlink attribute in 'msg'.  'offset' should be the value
     462                 :            :  * returned by nl_msg_start_nested(). */
     463                 :            : void
     464                 :      58243 : nl_msg_end_nested(struct ofpbuf *msg, size_t offset)
     465                 :            : {
     466                 :      58243 :     struct nlattr *attr = ofpbuf_at_assert(msg, offset, sizeof *attr);
     467                 :      58243 :     attr->nla_len = msg->size - offset;
     468                 :      58243 : }
     469                 :            : 
     470                 :            : /* Appends a nested Netlink attribute of the given 'type', with the 'size'
     471                 :            :  * bytes of content starting at 'data', to 'msg'. */
     472                 :            : void
     473                 :          3 : nl_msg_put_nested(struct ofpbuf *msg,
     474                 :            :                   uint16_t type, const void *data, size_t size)
     475                 :            : {
     476                 :          3 :     size_t offset = nl_msg_start_nested(msg, type);
     477                 :          3 :     nl_msg_put(msg, data, size);
     478                 :          3 :     nl_msg_end_nested(msg, offset);
     479                 :          3 : }
     480                 :            : 
     481                 :            : /* If 'buffer' begins with a valid "struct nlmsghdr", pulls the header and its
     482                 :            :  * payload off 'buffer', stores header and payload in 'msg->data' and
     483                 :            :  * 'msg->size', and returns a pointer to the header.
     484                 :            :  *
     485                 :            :  * If 'buffer' does not begin with a "struct nlmsghdr" or begins with one that
     486                 :            :  * is invalid, returns NULL and clears 'buffer' and 'msg'. */
     487                 :            : struct nlmsghdr *
     488                 :      79864 : nl_msg_next(struct ofpbuf *buffer, struct ofpbuf *msg)
     489                 :            : {
     490         [ +  - ]:      79864 :     if (buffer->size >= sizeof(struct nlmsghdr)) {
     491                 :      79864 :         struct nlmsghdr *nlmsghdr = nl_msg_nlmsghdr(buffer);
     492                 :      79864 :         size_t len = nlmsghdr->nlmsg_len;
     493 [ +  - ][ +  - ]:      79864 :         if (len >= sizeof *nlmsghdr && len <= buffer->size) {
     494                 :      79864 :             ofpbuf_use_const(msg, nlmsghdr, len);
     495                 :      79864 :             ofpbuf_pull(buffer, len);
     496                 :      79864 :             return nlmsghdr;
     497                 :            :         }
     498                 :            :     }
     499                 :            : 
     500                 :          0 :     ofpbuf_clear(buffer);
     501                 :          0 :     msg->data = NULL;
     502                 :          0 :     msg->size = 0;
     503                 :          0 :     return NULL;
     504                 :            : }
     505                 :            : 
     506                 :            : /* Returns true if a Netlink attribute with a payload that is 'payload_size'
     507                 :            :  * bytes long would be oversized, that is, if it's not possible to create an
     508                 :            :  * nlattr of that size because its size wouldn't fit in the 16-bit nla_len
     509                 :            :  * field. */
     510                 :            : bool
     511                 :     738340 : nl_attr_oversized(size_t payload_size)
     512                 :            : {
     513                 :     738340 :     return payload_size > UINT16_MAX - NLA_HDRLEN;
     514                 :            : }
     515                 :            : 
     516                 :            : /* Attributes. */
     517                 :            : 
     518                 :            : /* Returns the bits of 'nla->nla_type' that are significant for determining its
     519                 :            :  * type. */
     520                 :            : int
     521                 :   34650595 : nl_attr_type(const struct nlattr *nla)
     522                 :            : {
     523                 :   34650595 :     return nla->nla_type & NLA_TYPE_MASK;
     524                 :            : }
     525                 :            : 
     526                 :            : /* Returns the first byte in the payload of attribute 'nla'. */
     527                 :            : const void *
     528                 :     765732 : nl_attr_get(const struct nlattr *nla)
     529                 :            : {
     530         [ -  + ]:     765732 :     ovs_assert(nla->nla_len >= NLA_HDRLEN);
     531                 :     765732 :     return nla + 1;
     532                 :            : }
     533                 :            : 
     534                 :            : /* Returns the number of bytes in the payload of attribute 'nla'. */
     535                 :            : size_t
     536                 :   18187342 : nl_attr_get_size(const struct nlattr *nla)
     537                 :            : {
     538         [ -  + ]:   18187342 :     ovs_assert(nla->nla_len >= NLA_HDRLEN);
     539                 :   18187342 :     return nla->nla_len - NLA_HDRLEN;
     540                 :            : }
     541                 :            : 
     542                 :            : /* Asserts that 'nla''s payload is at least 'size' bytes long, and returns the
     543                 :            :  * first byte of the payload. */
     544                 :            : const void *
     545                 :   17290299 : nl_attr_get_unspec(const struct nlattr *nla, size_t size)
     546                 :            : {
     547         [ -  + ]:   17290299 :     ovs_assert(nla->nla_len >= NLA_HDRLEN + size);
     548                 :   17290299 :     return nla + 1;
     549                 :            : }
     550                 :            : 
     551                 :            : /* Returns true if 'nla' is nonnull.  (Some Netlink protocols use the presence
     552                 :            :  * or absence of an attribute as a Boolean flag.) */
     553                 :            : bool
     554                 :          0 : nl_attr_get_flag(const struct nlattr *nla)
     555                 :            : {
     556                 :          0 :     return nla != NULL;
     557                 :            : }
     558                 :            : 
     559                 :            : #define NL_ATTR_GET_AS(NLA, TYPE) \
     560                 :            :         (*(TYPE*) nl_attr_get_unspec(nla, sizeof(TYPE)))
     561                 :            : 
     562                 :            : /* Returns the 8-bit value in 'nla''s payload.
     563                 :            :  *
     564                 :            :  * Asserts that 'nla''s payload is at least 1 byte long. */
     565                 :            : uint8_t
     566                 :      87105 : nl_attr_get_u8(const struct nlattr *nla)
     567                 :            : {
     568                 :      87105 :     return NL_ATTR_GET_AS(nla, uint8_t);
     569                 :            : }
     570                 :            : 
     571                 :            : /* Returns the 16-bit host byte order value in 'nla''s payload.
     572                 :            :  *
     573                 :            :  * Asserts that 'nla''s payload is at least 2 bytes long. */
     574                 :            : uint16_t
     575                 :     146617 : nl_attr_get_u16(const struct nlattr *nla)
     576                 :            : {
     577                 :     146617 :     return NL_ATTR_GET_AS(nla, uint16_t);
     578                 :            : }
     579                 :            : 
     580                 :            : /* Returns the 32-bit host byte order value in 'nla''s payload.
     581                 :            :  *
     582                 :            :  * Asserts that 'nla''s payload is at least 4 bytes long. */
     583                 :            : uint32_t
     584                 :   16753836 : nl_attr_get_u32(const struct nlattr *nla)
     585                 :            : {
     586                 :   16753836 :     return NL_ATTR_GET_AS(nla, uint32_t);
     587                 :            : }
     588                 :            : 
     589                 :            : /* Returns the 64-bit host byte order value in 'nla''s payload.
     590                 :            :  *
     591                 :            :  * Asserts that 'nla''s payload is at least 8 bytes long. */
     592                 :            : uint64_t
     593                 :          0 : nl_attr_get_u64(const struct nlattr *nla)
     594                 :            : {
     595                 :          0 :     const ovs_32aligned_u64 *x = nl_attr_get_unspec(nla, sizeof *x);
     596                 :          0 :     return get_32aligned_u64(x);
     597                 :            : }
     598                 :            : 
     599                 :            : /* Returns the 16-bit network byte order value in 'nla''s payload.
     600                 :            :  *
     601                 :            :  * Asserts that 'nla''s payload is at least 2 bytes long. */
     602                 :            : ovs_be16
     603                 :     174663 : nl_attr_get_be16(const struct nlattr *nla)
     604                 :            : {
     605                 :     174663 :     return NL_ATTR_GET_AS(nla, ovs_be16);
     606                 :            : }
     607                 :            : 
     608                 :            : /* Returns the 32-bit network byte order value in 'nla''s payload.
     609                 :            :  *
     610                 :            :  * Asserts that 'nla''s payload is at least 4 bytes long. */
     611                 :            : ovs_be32
     612                 :      60169 : nl_attr_get_be32(const struct nlattr *nla)
     613                 :            : {
     614                 :      60169 :     return NL_ATTR_GET_AS(nla, ovs_be32);
     615                 :            : }
     616                 :            : 
     617                 :            : /* Returns the 64-bit network byte order value in 'nla''s payload.
     618                 :            :  *
     619                 :            :  * Asserts that 'nla''s payload is at least 8 bytes long. */
     620                 :            : ovs_be64
     621                 :      18396 : nl_attr_get_be64(const struct nlattr *nla)
     622                 :            : {
     623                 :      18396 :     const ovs_32aligned_be64 *x = nl_attr_get_unspec(nla, sizeof *x);
     624                 :      18396 :     return get_32aligned_be64(x);
     625                 :            : }
     626                 :            : 
     627                 :            : /* Returns the IPv6 address value in 'nla''s payload.
     628                 :            :  *
     629                 :            :  * Asserts that 'nla''s payload is at least 16 bytes long. */
     630                 :            : struct in6_addr
     631                 :      38718 : nl_attr_get_in6_addr(const struct nlattr *nla)
     632                 :            : {
     633                 :      38718 :     return NL_ATTR_GET_AS(nla, struct in6_addr);
     634                 :            : }
     635                 :            : 
     636                 :            : /* Returns the 32-bit odp_port_t value in 'nla''s payload.
     637                 :            :  *
     638                 :            :  * Asserts that 'nla''s payload is at least 4 bytes long. */
     639                 :            : odp_port_t
     640                 :     162938 : nl_attr_get_odp_port(const struct nlattr *nla)
     641                 :            : {
     642                 :     162938 :     return u32_to_odp(nl_attr_get_u32(nla));
     643                 :            : }
     644                 :            : 
     645                 :            : /* Returns the null-terminated string value in 'nla''s payload.
     646                 :            :  *
     647                 :            :  * Asserts that 'nla''s payload contains a null-terminated string. */
     648                 :            : const char *
     649                 :      11523 : nl_attr_get_string(const struct nlattr *nla)
     650                 :            : {
     651         [ -  + ]:      11523 :     ovs_assert(nla->nla_len > NLA_HDRLEN);
     652         [ -  + ]:      11523 :     ovs_assert(memchr(nl_attr_get(nla), '\0', nla->nla_len - NLA_HDRLEN));
     653                 :      11523 :     return nl_attr_get(nla);
     654                 :            : }
     655                 :            : 
     656                 :            : /* Initializes 'nested' to the payload of 'nla'. */
     657                 :            : void
     658                 :       3658 : nl_attr_get_nested(const struct nlattr *nla, struct ofpbuf *nested)
     659                 :            : {
     660                 :       3658 :     ofpbuf_use_const(nested, nl_attr_get(nla), nl_attr_get_size(nla));
     661                 :       3658 : }
     662                 :            : 
     663                 :            : /* Default minimum payload size for each type of attribute. */
     664                 :            : static size_t
     665                 :     189259 : min_attr_len(enum nl_attr_type type)
     666                 :            : {
     667   [ -  +  +  +  :     189259 :     switch (type) {
          +  +  +  +  +  
                   +  - ]
     668                 :          0 :     case NL_A_NO_ATTR: return 0;
     669                 :       9775 :     case NL_A_UNSPEC: return 0;
     670                 :       3474 :     case NL_A_U8: return 1;
     671                 :       3273 :     case NL_A_U16: return 2;
     672                 :     110362 :     case NL_A_U32: return 4;
     673                 :       4228 :     case NL_A_U64: return 8;
     674                 :      11523 :     case NL_A_STRING: return 1;
     675                 :        103 :     case NL_A_FLAG: return 0;
     676                 :      38707 :     case NL_A_IPV6: return 16;
     677                 :       7814 :     case NL_A_NESTED: return 0;
     678                 :          0 :     case N_NL_ATTR_TYPES: default: OVS_NOT_REACHED();
     679                 :            :     }
     680                 :            : }
     681                 :            : 
     682                 :            : /* Default maximum payload size for each type of attribute. */
     683                 :            : static size_t
     684                 :     193718 : max_attr_len(enum nl_attr_type type)
     685                 :            : {
     686   [ -  +  +  +  :     193718 :     switch (type) {
          +  +  +  +  +  
                   +  - ]
     687                 :          0 :     case NL_A_NO_ATTR: return SIZE_MAX;
     688                 :      20454 :     case NL_A_UNSPEC: return SIZE_MAX;
     689                 :       3474 :     case NL_A_U8: return 1;
     690                 :       3273 :     case NL_A_U16: return 2;
     691                 :     110362 :     case NL_A_U32: return 4;
     692                 :       4228 :     case NL_A_U64: return 8;
     693                 :       5303 :     case NL_A_STRING: return SIZE_MAX;
     694                 :        103 :     case NL_A_FLAG: return SIZE_MAX;
     695                 :      38707 :     case NL_A_IPV6: return 16;
     696                 :       7814 :     case NL_A_NESTED: return SIZE_MAX;
     697                 :          0 :     case N_NL_ATTR_TYPES: default: OVS_NOT_REACHED();
     698                 :            :     }
     699                 :            : }
     700                 :            : 
     701                 :            : bool
     702                 :     211764 : nl_attr_validate(const struct nlattr *nla, const struct nl_policy *policy)
     703                 :            : {
     704                 :     211764 :     uint16_t type = nl_attr_type(nla);
     705                 :            :     size_t min_len;
     706                 :            :     size_t max_len;
     707                 :            :     size_t len;
     708                 :            : 
     709         [ -  + ]:     211764 :     if (policy->type == NL_A_NO_ATTR) {
     710                 :          0 :         return true;
     711                 :            :     }
     712                 :            : 
     713                 :            :     /* Figure out min and max length. */
     714                 :     211764 :     min_len = policy->min_len;
     715         [ +  + ]:     211764 :     if (!min_len) {
     716                 :     189258 :         min_len = min_attr_len(policy->type);
     717                 :            :     }
     718                 :     211764 :     max_len = policy->max_len;
     719         [ +  + ]:     211764 :     if (!max_len) {
     720                 :     193717 :         max_len = max_attr_len(policy->type);
     721                 :            :     }
     722                 :            : 
     723                 :            :     /* Verify length. */
     724                 :     211763 :     len = nl_attr_get_size(nla);
     725 [ +  - ][ -  + ]:     211763 :     if (len < min_len || len > max_len) {
     726         [ #  # ]:          0 :         VLOG_DBG_RL(&rl, "attr %"PRIu16" length %"PRIuSIZE" not in "
     727                 :            :                     "allowed range %"PRIuSIZE"...%"PRIuSIZE, type, len, min_len, max_len);
     728                 :          0 :         return false;
     729                 :            :     }
     730                 :            : 
     731                 :            :     /* Strings must be null terminated and must not have embedded nulls. */
     732         [ +  + ]:     211763 :     if (policy->type == NL_A_STRING) {
     733         [ -  + ]:      11525 :         if (((char *) nla)[nla->nla_len - 1]) {
     734         [ #  # ]:          0 :             VLOG_DBG_RL(&rl, "attr %"PRIu16" lacks null at end", type);
     735                 :          0 :             return false;
     736                 :            :         }
     737         [ -  + ]:      11525 :         if (memchr(nla + 1, '\0', len - 1) != NULL) {
     738         [ #  # ]:          0 :             VLOG_DBG_RL(&rl, "attr %"PRIu16" has bad length", type);
     739                 :          0 :             return false;
     740                 :            :         }
     741                 :            :     }
     742                 :            : 
     743                 :     211763 :     return true;
     744                 :            : }
     745                 :            : 
     746                 :            : /* Parses the 'msg' starting at the given 'nla_offset' as a sequence of Netlink
     747                 :            :  * attributes.  'policy[i]', for 0 <= i < n_attrs, specifies how the attribute
     748                 :            :  * with nla_type == i is parsed; a pointer to attribute i is stored in
     749                 :            :  * attrs[i].  Returns true if successful, false on failure.
     750                 :            :  *
     751                 :            :  * If the Netlink attributes in 'msg' follow a Netlink header and a Generic
     752                 :            :  * Netlink header, then 'nla_offset' should be NLMSG_HDRLEN + GENL_HDRLEN. */
     753                 :            : bool
     754                 :      94250 : nl_policy_parse(const struct ofpbuf *msg, size_t nla_offset,
     755                 :            :                 const struct nl_policy policy[],
     756                 :            :                 struct nlattr *attrs[], size_t n_attrs)
     757                 :            : {
     758                 :            :     struct nlattr *nla;
     759                 :            :     size_t left;
     760                 :            :     size_t i;
     761                 :            : 
     762                 :      94250 :     memset(attrs, 0, n_attrs * sizeof *attrs);
     763                 :            : 
     764         [ -  + ]:      94250 :     if (msg->size < nla_offset) {
     765         [ #  # ]:          0 :         VLOG_DBG_RL(&rl, "missing headers in nl_policy_parse");
     766                 :          0 :         return false;
     767                 :            :     }
     768                 :            : 
     769         [ +  + ]:     607781 :     NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, nla_offset, 0),
     770                 :            :                       msg->size - nla_offset)
     771                 :            :     {
     772                 :     513532 :         uint16_t type = nl_attr_type(nla);
     773 [ +  + ][ +  + ]:     513532 :         if (type < n_attrs && policy[type].type != NL_A_NO_ATTR) {
     774                 :     211764 :             const struct nl_policy *e = &policy[type];
     775         [ -  + ]:     211764 :             if (!nl_attr_validate(nla, e)) {
     776                 :          0 :                 return false;
     777                 :            :             }
     778         [ -  + ]:     211763 :             if (attrs[type]) {
     779         [ #  # ]:          0 :                 VLOG_DBG_RL(&rl, "duplicate attr %"PRIu16, type);
     780                 :            :             }
     781                 :     211763 :             attrs[type] = nla;
     782                 :            :         }
     783                 :            :     }
     784         [ -  + ]:      94249 :     if (left) {
     785         [ #  # ]:          0 :         VLOG_DBG_RL(&rl, "attributes followed by garbage");
     786                 :          0 :         return false;
     787                 :            :     }
     788                 :            : 
     789         [ +  + ]:     755943 :     for (i = 0; i < n_attrs; i++) {
     790                 :     661694 :         const struct nl_policy *e = &policy[i];
     791 [ +  + ][ +  + ]:     661694 :         if (!e->optional && e->type != NL_A_NO_ATTR && !attrs[i]) {
                 [ -  + ]
     792         [ #  # ]:          0 :             VLOG_DBG_RL(&rl, "required attr %"PRIuSIZE" missing", i);
     793                 :          0 :             return false;
     794                 :            :         }
     795                 :            :     }
     796                 :      94249 :     return true;
     797                 :            : }
     798                 :            : 
     799                 :            : /* Parses the Netlink attributes within 'nla'.  'policy[i]', for 0 <= i <
     800                 :            :  * n_attrs, specifies how the attribute with nla_type == i is parsed; a pointer
     801                 :            :  * to attribute i is stored in attrs[i].  Returns true if successful, false on
     802                 :            :  * failure. */
     803                 :            : bool
     804                 :       3658 : nl_parse_nested(const struct nlattr *nla, const struct nl_policy policy[],
     805                 :            :                 struct nlattr *attrs[], size_t n_attrs)
     806                 :            : {
     807                 :            :     struct ofpbuf buf;
     808                 :            : 
     809                 :       3658 :     nl_attr_get_nested(nla, &buf);
     810                 :       3658 :     return nl_policy_parse(&buf, 0, policy, attrs, n_attrs);
     811                 :            : }
     812                 :            : 
     813                 :            : const struct nlattr *
     814                 :      55062 : nl_attr_find__(const struct nlattr *attrs, size_t size, uint16_t type)
     815                 :            : {
     816                 :            :     const struct nlattr *nla;
     817                 :            :     size_t left;
     818                 :            : 
     819         [ +  + ]:     416026 :     NL_ATTR_FOR_EACH (nla, left, attrs, size) {
     820         [ +  + ]:     403672 :         if (nl_attr_type(nla) == type) {
     821                 :      42708 :             return nla;
     822                 :            :         }
     823                 :            :     }
     824                 :      12354 :     return NULL;
     825                 :            : }
     826                 :            : 
     827                 :            : /* Returns the first Netlink attribute within 'buf' with the specified 'type',
     828                 :            :  * skipping a header of 'hdr_len' bytes at the beginning of 'buf'.
     829                 :            :  *
     830                 :            :  * This function does not validate the attribute's length. */
     831                 :            : const struct nlattr *
     832                 :        425 : nl_attr_find(const struct ofpbuf *buf, size_t hdr_len, uint16_t type)
     833                 :            : {
     834                 :        425 :     return nl_attr_find__(ofpbuf_at(buf, hdr_len, 0), buf->size - hdr_len,
     835                 :            :                           type);
     836                 :            : }
     837                 :            : 
     838                 :            : /* Returns the first Netlink attribute within 'nla' with the specified
     839                 :            :  * 'type'.
     840                 :            :  *
     841                 :            :  * This function does not validate the attribute's length. */
     842                 :            : const struct nlattr *
     843                 :      14541 : nl_attr_find_nested(const struct nlattr *nla, uint16_t type)
     844                 :            : {
     845                 :      14541 :     return nl_attr_find__(nl_attr_get(nla), nl_attr_get_size(nla), type);
     846                 :            : }

Generated by: LCOV version 1.12