LCOV - code coverage report
Current view: top level - lib - netlink-conntrack.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 173 289 59.9 %
Date: 2016-09-14 01:02:56 Functions: 17 22 77.3 %
Branches: 73 202 36.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 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                 :            : 
      19                 :            : #include "netlink-conntrack.h"
      20                 :            : 
      21                 :            : #include <linux/netfilter/nfnetlink.h>
      22                 :            : #include <linux/netfilter/nfnetlink_conntrack.h>
      23                 :            : #include <linux/netfilter/nf_conntrack_common.h>
      24                 :            : #include <linux/netfilter/nf_conntrack_tcp.h>
      25                 :            : #include <linux/netfilter/nf_conntrack_ftp.h>
      26                 :            : #include <linux/netfilter/nf_conntrack_sctp.h>
      27                 :            : 
      28                 :            : #include "byte-order.h"
      29                 :            : #include "compiler.h"
      30                 :            : #include "openvswitch/dynamic-string.h"
      31                 :            : #include "netlink.h"
      32                 :            : #include "netlink-socket.h"
      33                 :            : #include "openvswitch/ofpbuf.h"
      34                 :            : #include "openvswitch/vlog.h"
      35                 :            : #include "poll-loop.h"
      36                 :            : #include "timeval.h"
      37                 :            : #include "unixctl.h"
      38                 :            : #include "util.h"
      39                 :            : 
      40                 :      20190 : VLOG_DEFINE_THIS_MODULE(netlink_conntrack);
      41                 :            : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
      42                 :            : 
      43                 :            : /* This module works only if conntrack modules and features are enabled in the
      44                 :            :  * Linux kernel.  This can be done from a root shell like this:
      45                 :            :  *
      46                 :            :  * $ modprobe ip_conntrack
      47                 :            :  * $ sysctl -w net.netfilter.nf_conntrack_acct=1
      48                 :            :  * $ sysctl -w net.netfilter.nf_conntrack_timestamp=1
      49                 :            :  *
      50                 :            :  * Also, if testing conntrack label feature without conntrack-aware OVS kernel
      51                 :            :  * module, there must be a connlabel rule in iptables for space to be reserved
      52                 :            :  * for the labels (see kernel source connlabel_mt_check()).  Such a rule can be
      53                 :            :  * inserted from a root shell like this:
      54                 :            :  *
      55                 :            :  * $ iptables -A INPUT -m conntrack -m connlabel \
      56                 :            :  *   --ctstate NEW,ESTABLISHED,RELATED --label 127 -j ACCEPT
      57                 :            :  */
      58                 :            : 
      59                 :            : /* Some attributes were introduced in later kernels: with these definitions
      60                 :            :  * we should be able to compile userspace against Linux 2.6.32+. */
      61                 :            : 
      62                 :            : #define CTA_ZONE          (CTA_SECMARK + 1)
      63                 :            : #define CTA_SECCTX        (CTA_SECMARK + 2)
      64                 :            : #define CTA_TIMESTAMP     (CTA_SECMARK + 3)
      65                 :            : #define CTA_MARK_MASK     (CTA_SECMARK + 4)
      66                 :            : #define CTA_LABELS        (CTA_SECMARK + 5)
      67                 :            : #define CTA_LABELS_MASK   (CTA_SECMARK + 6)
      68                 :            : 
      69                 :            : #define CTA_TIMESTAMP_START 1
      70                 :            : #define CTA_TIMESTAMP_STOP  2
      71                 :            : 
      72                 :            : #define IPS_TEMPLATE_BIT 11
      73                 :            : #define IPS_TEMPLATE (1 << IPS_TEMPLATE_BIT)
      74                 :            : 
      75                 :            : #define IPS_UNTRACKED_BIT 12
      76                 :            : #define IPS_UNTRACKED (1 << IPS_UNTRACKED_BIT)
      77                 :            : 
      78                 :            : static const struct nl_policy nfnlgrp_conntrack_policy[] = {
      79                 :            :     [CTA_TUPLE_ORIG] = { .type = NL_A_NESTED, .optional = false },
      80                 :            :     [CTA_TUPLE_REPLY] = { .type = NL_A_NESTED, .optional = false },
      81                 :            :     [CTA_ZONE] = { .type = NL_A_BE16, .optional = true },
      82                 :            :     [CTA_STATUS] = { .type = NL_A_BE32, .optional = false },
      83                 :            :     [CTA_TIMESTAMP] = { .type = NL_A_NESTED, .optional = true },
      84                 :            :     [CTA_TIMEOUT] = { .type = NL_A_BE32, .optional = true },
      85                 :            :     [CTA_COUNTERS_ORIG] = { .type = NL_A_NESTED, .optional = true },
      86                 :            :     [CTA_COUNTERS_REPLY] = { .type = NL_A_NESTED, .optional = true },
      87                 :            :     [CTA_PROTOINFO] = { .type = NL_A_NESTED, .optional = true },
      88                 :            :     [CTA_HELP] = { .type = NL_A_NESTED, .optional = true },
      89                 :            :     [CTA_MARK] = { .type = NL_A_BE32, .optional = true },
      90                 :            :     [CTA_SECCTX] = { .type = NL_A_NESTED, .optional = true },
      91                 :            :     [CTA_ID] = { .type = NL_A_BE32, .optional = false },
      92                 :            :     [CTA_USE] = { .type = NL_A_BE32, .optional = true },
      93                 :            :     [CTA_TUPLE_MASTER] = { .type = NL_A_NESTED, .optional = true },
      94                 :            :     [CTA_NAT_SEQ_ADJ_ORIG] = { .type = NL_A_NESTED, .optional = true },
      95                 :            :     [CTA_NAT_SEQ_ADJ_REPLY] = { .type = NL_A_NESTED, .optional = true },
      96                 :            :     [CTA_LABELS] = { .type = NL_A_UNSPEC, .optional = true },
      97                 :            :     /* CTA_NAT_SRC, CTA_NAT_DST, CTA_TIMESTAMP, CTA_MARK_MASK, and
      98                 :            :      * CTA_LABELS_MASK are not received from kernel. */
      99                 :            : };
     100                 :            : 
     101                 :            : /* Declarations for conntrack netlink dumping. */
     102                 :            : static void nl_msg_put_nfgenmsg(struct ofpbuf *msg, size_t expected_payload,
     103                 :            :                                 int family, uint8_t subsystem, uint8_t cmd,
     104                 :            :                                 uint32_t flags);
     105                 :            : 
     106                 :            : static bool nl_ct_parse_header_policy(struct ofpbuf *buf,
     107                 :            :         enum nl_ct_event_type *event_type,
     108                 :            :         uint8_t *nfgen_family,
     109                 :            :         struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)]);
     110                 :            : 
     111                 :            : static bool nl_ct_attrs_to_ct_dpif_entry(struct ct_dpif_entry *entry,
     112                 :            :         struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)],
     113                 :            :         uint8_t nfgen_family);
     114                 :            : 
     115                 :            : struct nl_ct_dump_state {
     116                 :            :     struct nl_dump dump;
     117                 :            :     struct ofpbuf buf;
     118                 :            :     bool filter_zone;
     119                 :            :     uint16_t zone;
     120                 :            : };
     121                 :            : 
     122                 :            : /* Conntrack netlink dumping. */
     123                 :            : 
     124                 :            : /* Initialize a conntrack netlink dump. */
     125                 :            : int
     126                 :         53 : nl_ct_dump_start(struct nl_ct_dump_state **statep, const uint16_t *zone)
     127                 :            : {
     128                 :            :     struct nl_ct_dump_state *state;
     129                 :            : 
     130                 :         53 :     *statep = state = xzalloc(sizeof *state);
     131                 :         53 :     ofpbuf_init(&state->buf, NL_DUMP_BUFSIZE);
     132                 :            : 
     133         [ -  + ]:         53 :     if (zone) {
     134                 :          0 :         state->filter_zone = true;
     135                 :          0 :         state->zone = *zone;
     136                 :            :     }
     137                 :            : 
     138                 :         53 :     nl_msg_put_nfgenmsg(&state->buf, 0, AF_UNSPEC, NFNL_SUBSYS_CTNETLINK,
     139                 :            :                         IPCTNL_MSG_CT_GET, NLM_F_REQUEST);
     140                 :         53 :     nl_dump_start(&state->dump, NETLINK_NETFILTER, &state->buf);
     141                 :         53 :     ofpbuf_clear(&state->buf);
     142                 :            : 
     143                 :         53 :     return 0;
     144                 :            : }
     145                 :            : 
     146                 :            : /* Receive the next 'entry' from the conntrack netlink dump with 'state'.
     147                 :            :  * Returns 'EOF' when no more entries are available, 0 otherwise.  'entry' may
     148                 :            :  * be uninitilized memory on entry, and must be uninitialized with
     149                 :            :  * ct_dpif_entry_uninit() afterwards by the caller.  In case the same 'entry' is
     150                 :            :  * passed to this function again, the entry must also be uninitialized before
     151                 :            :  * the next call. */
     152                 :            : int
     153                 :        439 : nl_ct_dump_next(struct nl_ct_dump_state *state, struct ct_dpif_entry *entry)
     154                 :            : {
     155                 :            :     struct ofpbuf buf;
     156                 :            : 
     157                 :        439 :     memset(entry, 0, sizeof *entry);
     158                 :            :     for (;;) {
     159                 :            :         struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)];
     160                 :            :         enum nl_ct_event_type type;
     161                 :            :         uint8_t nfgen_family;
     162                 :            : 
     163         [ +  + ]:        439 :         if (!nl_dump_next(&state->dump, &buf, &state->buf)) {
     164                 :         53 :             return EOF;
     165                 :            :         }
     166                 :            : 
     167         [ -  + ]:        386 :         if (!nl_ct_parse_header_policy(&buf, &type, &nfgen_family, attrs)) {
     168                 :          0 :             continue;
     169                 :            :         };
     170                 :            : 
     171         [ -  + ]:        386 :         if (state->filter_zone) {
     172         [ #  # ]:          0 :             uint16_t entry_zone = attrs[CTA_ZONE]
     173                 :          0 :                                   ? ntohs(nl_attr_get_be16(attrs[CTA_ZONE]))
     174                 :            :                                   : 0;
     175         [ #  # ]:          0 :             if (entry_zone != state->zone) {
     176                 :          0 :                 continue;
     177                 :            :             }
     178                 :            :         }
     179                 :            : 
     180         [ +  - ]:        386 :         if (nl_ct_attrs_to_ct_dpif_entry(entry, attrs, nfgen_family)) {
     181                 :        386 :             break;
     182                 :            :         }
     183                 :            : 
     184                 :          0 :         ct_dpif_entry_uninit(entry);
     185                 :          0 :         memset(entry, 0, sizeof *entry);
     186                 :            :         /* Ignore the failed entry and get the next one. */
     187                 :        439 :     }
     188                 :            : 
     189                 :        386 :     ofpbuf_uninit(&buf);
     190                 :        386 :     return 0;
     191                 :            : }
     192                 :            : 
     193                 :            : /* End a conntrack netlink dump. */
     194                 :            : int
     195                 :         53 : nl_ct_dump_done(struct nl_ct_dump_state *state)
     196                 :            : {
     197                 :         53 :     int error = nl_dump_done(&state->dump);
     198                 :            : 
     199                 :         53 :     ofpbuf_uninit(&state->buf);
     200                 :         53 :     free(state);
     201                 :         53 :     return error;
     202                 :            : }
     203                 :            : 
     204                 :            : /* Format conntrack event 'entry' of 'type' to 'ds'. */
     205                 :            : void
     206                 :          0 : nl_ct_format_event_entry(const struct ct_dpif_entry *entry,
     207                 :            :                          enum nl_ct_event_type type, struct ds *ds,
     208                 :            :                          bool verbose, bool print_stats)
     209                 :            : {
     210         [ #  # ]:          0 :     ds_put_format(ds, "%s ",
     211                 :            :                   type == NL_CT_EVENT_NEW ? "NEW"
     212                 :            :                   : type == NL_CT_EVENT_UPDATE ? "UPDATE"
     213         [ #  # ]:          0 :                   : type == NL_CT_EVENT_DELETE ? "DELETE"
     214         [ #  # ]:          0 :                   : "UNKNOWN");
     215                 :          0 :     ct_dpif_format_entry(entry, ds, verbose, print_stats);
     216                 :          0 : }
     217                 :            : 
     218                 :            : int
     219                 :         60 : nl_ct_flush(void)
     220                 :            : {
     221                 :            :     struct ofpbuf buf;
     222                 :            :     int err;
     223                 :            : 
     224                 :         60 :     ofpbuf_init(&buf, NL_DUMP_BUFSIZE);
     225                 :            : 
     226                 :         60 :     nl_msg_put_nfgenmsg(&buf, 0, AF_UNSPEC, NFNL_SUBSYS_CTNETLINK,
     227                 :            :                         IPCTNL_MSG_CT_DELETE, NLM_F_REQUEST);
     228                 :            : 
     229                 :         60 :     err = nl_transact(NETLINK_NETFILTER, &buf, NULL);
     230                 :         60 :     ofpbuf_uninit(&buf);
     231                 :            : 
     232                 :            :     /* Expectations are flushed automatically, because they do not
     233                 :            :      * have a master connection anymore */
     234                 :            : 
     235                 :         60 :     return err;
     236                 :            : }
     237                 :            : 
     238                 :            : #ifdef _WIN32
     239                 :            : int
     240                 :            : nl_ct_flush_zone(uint16_t flush_zone)
     241                 :            : {
     242                 :            :     /* Windows can flush a specific zone */
     243                 :            :     struct ofpbuf buf;
     244                 :            :     int err;
     245                 :            : 
     246                 :            :     ofpbuf_init(&buf, NL_DUMP_BUFSIZE);
     247                 :            : 
     248                 :            :     nl_msg_put_nfgenmsg(&buf, 0, AF_UNSPEC, NFNL_SUBSYS_CTNETLINK,
     249                 :            :                         IPCTNL_MSG_CT_DELETE, NLM_F_REQUEST);
     250                 :            :     nl_msg_put_be16(&buf, CTA_ZONE, flush_zone);
     251                 :            : 
     252                 :            :     err = nl_transact(NETLINK_NETFILTER, &buf, NULL);
     253                 :            :     ofpbuf_uninit(&buf);
     254                 :            : 
     255                 :            :     return err;
     256                 :            : }
     257                 :            : #else
     258                 :            : int
     259                 :          0 : nl_ct_flush_zone(uint16_t flush_zone)
     260                 :            : {
     261                 :            :     /* Apparently, there's no netlink interface to flush a specific zone.
     262                 :            :      * This code dumps every connection, checks the zone and eventually
     263                 :            :      * delete the entry.
     264                 :            :      *
     265                 :            :      * This is race-prone, but it is better than using shell scripts. */
     266                 :            : 
     267                 :            :     struct nl_dump dump;
     268                 :            :     struct ofpbuf buf, reply, delete;
     269                 :            : 
     270                 :          0 :     ofpbuf_init(&buf, NL_DUMP_BUFSIZE);
     271                 :          0 :     ofpbuf_init(&delete, NL_DUMP_BUFSIZE);
     272                 :            : 
     273                 :          0 :     nl_msg_put_nfgenmsg(&buf, 0, AF_UNSPEC, NFNL_SUBSYS_CTNETLINK,
     274                 :            :                         IPCTNL_MSG_CT_GET, NLM_F_REQUEST);
     275                 :          0 :     nl_dump_start(&dump, NETLINK_NETFILTER, &buf);
     276                 :          0 :     ofpbuf_clear(&buf);
     277                 :            : 
     278                 :            :     for (;;) {
     279                 :            :         struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)];
     280                 :            :         enum nl_ct_event_type event_type;
     281                 :            :         uint8_t nfgen_family;
     282                 :          0 :         uint16_t zone = 0;
     283                 :            : 
     284         [ #  # ]:          0 :         if (!nl_dump_next(&dump, &reply, &buf)) {
     285                 :          0 :             break;
     286                 :            :         }
     287                 :            : 
     288         [ #  # ]:          0 :         if (!nl_ct_parse_header_policy(&reply, &event_type, &nfgen_family,
     289                 :            :                                        attrs)) {
     290                 :          0 :             continue;
     291                 :            :         };
     292                 :            : 
     293         [ #  # ]:          0 :         if (attrs[CTA_ZONE]) {
     294                 :          0 :             zone = ntohs(nl_attr_get_be16(attrs[CTA_ZONE]));
     295                 :            :         }
     296                 :            : 
     297         [ #  # ]:          0 :         if (zone != flush_zone) {
     298                 :            :             /* The entry is not in the zone we're flushing. */
     299                 :          0 :             continue;
     300                 :            :         }
     301                 :          0 :         nl_msg_put_nfgenmsg(&delete, 0, nfgen_family, NFNL_SUBSYS_CTNETLINK,
     302                 :            :                             IPCTNL_MSG_CT_DELETE, NLM_F_REQUEST);
     303                 :            : 
     304                 :          0 :         nl_msg_put_be16(&delete, CTA_ZONE, htons(zone));
     305                 :          0 :         nl_msg_put_unspec(&delete, CTA_TUPLE_ORIG, attrs[CTA_TUPLE_ORIG] + 1,
     306                 :          0 :                           attrs[CTA_TUPLE_ORIG]->nla_len - NLA_HDRLEN);
     307                 :          0 :         nl_msg_put_unspec(&delete, CTA_ID, attrs[CTA_ID] + 1,
     308                 :          0 :                           attrs[CTA_ID]->nla_len - NLA_HDRLEN);
     309                 :          0 :         nl_transact(NETLINK_NETFILTER, &delete, NULL);
     310                 :          0 :         ofpbuf_clear(&delete);
     311                 :          0 :     }
     312                 :            : 
     313                 :          0 :     nl_dump_done(&dump);
     314                 :            : 
     315                 :          0 :     ofpbuf_uninit(&delete);
     316                 :          0 :     ofpbuf_uninit(&buf);
     317                 :            : 
     318                 :            :     /* Expectations are flushed automatically, because they do not
     319                 :            :      * have a master connection anymore */
     320                 :          0 :     return 0;
     321                 :            : }
     322                 :            : #endif
     323                 :            : 
     324                 :            : /* Conntrack netlink parsing. */
     325                 :            : 
     326                 :            : static bool
     327                 :          0 : nl_ct_parse_counters(struct nlattr *nla, struct ct_dpif_counters *counters)
     328                 :            : {
     329                 :            :     static const struct nl_policy policy[] = {
     330                 :            :         [CTA_COUNTERS_PACKETS] = { .type = NL_A_BE64, .optional = false },
     331                 :            :         [CTA_COUNTERS_BYTES] = { .type = NL_A_BE64, .optional = false },
     332                 :            :     };
     333                 :            :     struct nlattr *attrs[ARRAY_SIZE(policy)];
     334                 :            :     bool parsed;
     335                 :            : 
     336                 :          0 :     parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));
     337                 :            : 
     338         [ #  # ]:          0 :     if (parsed) {
     339                 :            :         counters->packets
     340                 :          0 :             = ntohll(nl_attr_get_be64(attrs[CTA_COUNTERS_PACKETS]));
     341                 :          0 :         counters->bytes = ntohll(nl_attr_get_be64(attrs[CTA_COUNTERS_BYTES]));
     342                 :            :     } else {
     343         [ #  # ]:          0 :         VLOG_ERR_RL(&rl, "Could not parse nested counters. "
     344                 :            :                     "Possibly incompatible Linux kernel version.");
     345                 :            :     }
     346                 :            : 
     347                 :          0 :     return parsed;
     348                 :            : }
     349                 :            : 
     350                 :            : static bool
     351                 :          0 : nl_ct_parse_timestamp(struct nlattr *nla, struct ct_dpif_timestamp *timestamp)
     352                 :            : {
     353                 :            :     static const struct nl_policy policy[] = {
     354                 :            :         [CTA_TIMESTAMP_START] = { .type = NL_A_BE64, .optional = false },
     355                 :            :         [CTA_TIMESTAMP_STOP] = { .type = NL_A_BE64, .optional = true },
     356                 :            :     };
     357                 :            :     struct nlattr *attrs[ARRAY_SIZE(policy)];
     358                 :            :     bool parsed;
     359                 :            : 
     360                 :          0 :     parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));
     361                 :            : 
     362         [ #  # ]:          0 :     if (parsed) {
     363                 :            :         timestamp->start
     364                 :          0 :             = ntohll(nl_attr_get_be64(attrs[CTA_TIMESTAMP_START]));
     365         [ #  # ]:          0 :         if (attrs[CTA_TIMESTAMP_STOP]) {
     366                 :            :             timestamp->stop
     367                 :          0 :                 = ntohll(nl_attr_get_be64(attrs[CTA_TIMESTAMP_STOP]));
     368                 :            :         }
     369                 :            :     } else {
     370         [ #  # ]:          0 :         VLOG_ERR_RL(&rl, "Could not parse nested timestamp. "
     371                 :            :                     "Possibly incompatible Linux kernel version.");
     372                 :            :     }
     373                 :            : 
     374                 :          0 :     return parsed;
     375                 :            : }
     376                 :            : 
     377                 :            : static bool
     378                 :        783 : nl_ct_parse_tuple_ip(struct nlattr *nla, struct ct_dpif_tuple *tuple)
     379                 :            : {
     380                 :            :     static const struct nl_policy policy[] = {
     381                 :            :         [CTA_IP_V4_SRC] = { .type = NL_A_BE32, .optional = true },
     382                 :            :         [CTA_IP_V4_DST] = { .type = NL_A_BE32, .optional = true },
     383                 :            :         [CTA_IP_V6_SRC] = { NL_POLICY_FOR(struct in6_addr), .optional = true },
     384                 :            :         [CTA_IP_V6_DST] = { NL_POLICY_FOR(struct in6_addr), .optional = true },
     385                 :            :     };
     386                 :            :     struct nlattr *attrs[ARRAY_SIZE(policy)];
     387                 :            :     bool parsed;
     388                 :            : 
     389                 :        783 :     parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));
     390                 :            : 
     391         [ +  - ]:        783 :     if (parsed) {
     392         [ +  + ]:        783 :         if (tuple->l3_type == AF_INET) {
     393         [ +  - ]:        769 :             if (attrs[CTA_IP_V4_SRC]) {
     394                 :        769 :                 tuple->src.ip = nl_attr_get_be32(attrs[CTA_IP_V4_SRC]);
     395                 :            :             }
     396         [ +  - ]:        769 :             if (attrs[CTA_IP_V4_DST]) {
     397                 :        769 :                 tuple->dst.ip = nl_attr_get_be32(attrs[CTA_IP_V4_DST]);
     398                 :            :             }
     399         [ +  - ]:         14 :         } else if (tuple->l3_type == AF_INET6) {
     400         [ +  - ]:         14 :             if (attrs[CTA_IP_V6_SRC]) {
     401                 :         14 :                 memcpy(&tuple->src.in6, nl_attr_get(attrs[CTA_IP_V6_SRC]),
     402                 :            :                        sizeof tuple->src.in6);
     403                 :            :             }
     404         [ +  - ]:         14 :             if (attrs[CTA_IP_V6_DST]) {
     405                 :         14 :                 memcpy(&tuple->dst.in6, nl_attr_get(attrs[CTA_IP_V6_DST]),
     406                 :            :                        sizeof tuple->dst.in6);
     407                 :            :             }
     408                 :            :         } else {
     409         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "Unsupported IP protocol: %u.", tuple->l3_type);
     410                 :          0 :             return false;
     411                 :            :         }
     412                 :            :     } else {
     413         [ #  # ]:          0 :         VLOG_ERR_RL(&rl, "Could not parse nested tuple IP options. "
     414                 :            :                     "Possibly incompatible Linux kernel version.");
     415                 :            :     }
     416                 :            : 
     417                 :        783 :     return parsed;
     418                 :            : }
     419                 :            : 
     420                 :            : static bool
     421                 :        783 : nl_ct_parse_tuple_proto(struct nlattr *nla, struct ct_dpif_tuple *tuple)
     422                 :            : {
     423                 :            :     static const struct nl_policy policy[] = {
     424                 :            :         [CTA_PROTO_NUM] = { .type = NL_A_U8, .optional = false },
     425                 :            :         [CTA_PROTO_SRC_PORT] = { .type = NL_A_BE16, .optional = true },
     426                 :            :         [CTA_PROTO_DST_PORT] = { .type = NL_A_BE16, .optional = true },
     427                 :            :         [CTA_PROTO_ICMP_ID] = { .type = NL_A_BE16, .optional = true },
     428                 :            :         [CTA_PROTO_ICMP_TYPE] = { .type = NL_A_U8, .optional = true },
     429                 :            :         [CTA_PROTO_ICMP_CODE] = { .type = NL_A_U8, .optional = true },
     430                 :            :         [CTA_PROTO_ICMPV6_ID] = { .type = NL_A_BE16, .optional = true },
     431                 :            :         [CTA_PROTO_ICMPV6_TYPE] = { .type = NL_A_U8, .optional = true },
     432                 :            :         [CTA_PROTO_ICMPV6_CODE] = { .type = NL_A_U8, .optional = true },
     433                 :            :     };
     434                 :            :     struct nlattr *attrs[ARRAY_SIZE(policy)];
     435                 :            :     bool parsed;
     436                 :            : 
     437                 :        783 :     parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));
     438                 :            : 
     439         [ +  - ]:        783 :     if (parsed) {
     440                 :        783 :         tuple->ip_proto = nl_attr_get_u8(attrs[CTA_PROTO_NUM]);
     441                 :            : 
     442 [ +  + ][ +  + ]:        783 :         if (tuple->l3_type == AF_INET && tuple->ip_proto == IPPROTO_ICMP) {
     443 [ +  - ][ +  - ]:         30 :             if (!attrs[CTA_PROTO_ICMP_ID] || !attrs[CTA_PROTO_ICMP_TYPE]
     444         [ -  + ]:         30 :                 || !attrs[CTA_PROTO_ICMP_CODE]) {
     445         [ #  # ]:          0 :                 VLOG_ERR_RL(&rl, "Tuple ICMP data missing.");
     446                 :          0 :                 return false;
     447                 :            :             }
     448                 :         30 :             tuple->icmp_id = nl_attr_get_be16(attrs[CTA_PROTO_ICMP_ID]);
     449                 :         30 :             tuple->icmp_type = nl_attr_get_u8(attrs[CTA_PROTO_ICMP_TYPE]);
     450                 :         30 :             tuple->icmp_code = nl_attr_get_u8(attrs[CTA_PROTO_ICMP_CODE]);
     451 [ +  + ][ +  + ]:        753 :         } else if (tuple->l3_type == AF_INET6 &&
     452                 :         14 :                    tuple->ip_proto == IPPROTO_ICMPV6) {
     453 [ +  - ][ +  - ]:          2 :             if (!attrs[CTA_PROTO_ICMPV6_ID] || !attrs[CTA_PROTO_ICMPV6_TYPE]
     454         [ -  + ]:          2 :                 || !attrs[CTA_PROTO_ICMPV6_CODE]) {
     455         [ #  # ]:          0 :                 VLOG_ERR_RL(&rl, "Tuple ICMPv6 data missing.");
     456                 :          0 :                 return false;
     457                 :            :             }
     458                 :          2 :             tuple->icmp_id = nl_attr_get_be16(attrs[CTA_PROTO_ICMPV6_ID]);
     459                 :          2 :             tuple->icmp_type = nl_attr_get_u8(attrs[CTA_PROTO_ICMPV6_TYPE]);
     460                 :          2 :             tuple->icmp_code = nl_attr_get_u8(attrs[CTA_PROTO_ICMPV6_CODE]);
     461 [ +  - ][ +  - ]:        751 :         } else if (attrs[CTA_PROTO_SRC_PORT] && attrs[CTA_PROTO_DST_PORT]) {
     462                 :        751 :             tuple->src_port = nl_attr_get_be16(attrs[CTA_PROTO_SRC_PORT]);
     463                 :        751 :             tuple->dst_port = nl_attr_get_be16(attrs[CTA_PROTO_DST_PORT]);
     464                 :            :         } else {
     465                 :            :             /* Unsupported IPPROTO and no ports, leave them zeroed.
     466                 :            :              * We have parsed the ip_proto, so this is not a total failure. */
     467         [ #  # ]:        783 :             VLOG_INFO_RL(&rl, "Unsupported L4 protocol: %u.", tuple->ip_proto);
     468                 :            :         }
     469                 :            :     } else {
     470         [ #  # ]:          0 :         VLOG_ERR_RL(&rl, "Could not parse nested tuple protocol options. "
     471                 :            :                     "Possibly incompatible Linux kernel version.");
     472                 :            :     }
     473                 :            : 
     474                 :        783 :     return parsed;
     475                 :            : }
     476                 :            : 
     477                 :            : static bool
     478                 :        783 : nl_ct_parse_tuple(struct nlattr *nla, struct ct_dpif_tuple *tuple,
     479                 :            :                   uint16_t l3_type)
     480                 :            : {
     481                 :            :     static const struct nl_policy policy[] = {
     482                 :            :         [CTA_TUPLE_IP] = { .type = NL_A_NESTED, .optional = false },
     483                 :            :         [CTA_TUPLE_PROTO] = { .type = NL_A_NESTED, .optional = false },
     484                 :            :     };
     485                 :            :     struct nlattr *attrs[ARRAY_SIZE(policy)];
     486                 :            :     bool parsed;
     487                 :            : 
     488                 :        783 :     parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));
     489                 :            : 
     490                 :        783 :     memset(tuple, 0, sizeof *tuple);
     491                 :            : 
     492         [ +  - ]:        783 :     if (parsed) {
     493                 :        783 :         tuple->l3_type = l3_type;
     494                 :            : 
     495         [ +  - ]:        783 :         if (!nl_ct_parse_tuple_ip(attrs[CTA_TUPLE_IP], tuple)
     496         [ -  + ]:        783 :             || !nl_ct_parse_tuple_proto(attrs[CTA_TUPLE_PROTO], tuple)) {
     497                 :            :             struct ds ds;
     498                 :            : 
     499                 :          0 :             ds_init(&ds);
     500                 :          0 :             ct_dpif_format_tuple(&ds, tuple);
     501                 :            : 
     502         [ #  # ]:          0 :             VLOG_ERR_RL(&rl, "Failed to parse tuple: %s", ds_cstr(&ds));
     503                 :          0 :             ds_destroy(&ds);
     504                 :            : 
     505                 :          0 :             memset(tuple, 0, sizeof *tuple);
     506                 :          0 :             return false;
     507                 :            :         }
     508                 :            :     } else {
     509         [ #  # ]:          0 :         VLOG_ERR_RL(&rl, "Could not parse nested tuple options. "
     510                 :            :                     "Possibly incompatible Linux kernel version.");
     511                 :            :     }
     512                 :            : 
     513                 :        783 :     return parsed;
     514                 :            : }
     515                 :            : 
     516                 :            : /* Translate netlink TCP state to CT_DPIF_TCP state. */
     517                 :            : static uint8_t
     518                 :        368 : nl_ct_tcp_state_to_dpif(uint8_t state)
     519                 :            : {
     520                 :            : #ifdef _WIN32
     521                 :            :     /* Windows currently sends up CT_DPIF_TCP state */
     522                 :            :     return state;
     523                 :            : #else
     524   [ -  +  -  +  :        368 :     switch (state) {
          +  +  -  -  +  
                   -  - ]
     525                 :            :     case TCP_CONNTRACK_NONE:
     526                 :          0 :         return CT_DPIF_TCPS_CLOSED;
     527                 :            :     case TCP_CONNTRACK_SYN_SENT:
     528                 :          3 :         return CT_DPIF_TCPS_SYN_SENT;
     529                 :            :     case TCP_CONNTRACK_SYN_SENT2:
     530                 :          0 :         return CT_DPIF_TCPS_SYN_SENT;
     531                 :            :     case TCP_CONNTRACK_SYN_RECV:
     532                 :          8 :         return CT_DPIF_TCPS_SYN_RECV;
     533                 :            :     case TCP_CONNTRACK_ESTABLISHED:
     534                 :         42 :         return CT_DPIF_TCPS_ESTABLISHED;
     535                 :            :     case TCP_CONNTRACK_FIN_WAIT:
     536                 :          1 :         return CT_DPIF_TCPS_FIN_WAIT_1;
     537                 :            :     case TCP_CONNTRACK_CLOSE_WAIT:
     538                 :          0 :         return CT_DPIF_TCPS_CLOSE_WAIT;
     539                 :            :     case TCP_CONNTRACK_LAST_ACK:
     540                 :          0 :         return CT_DPIF_TCPS_LAST_ACK;
     541                 :            :     case TCP_CONNTRACK_TIME_WAIT:
     542                 :        314 :         return CT_DPIF_TCPS_TIME_WAIT;
     543                 :            :     case TCP_CONNTRACK_CLOSE:
     544                 :          0 :         return CT_DPIF_TCPS_CLOSING;
     545                 :            :     default:
     546                 :          0 :         return CT_DPIF_TCPS_CLOSED;
     547                 :            :     }
     548                 :            : #endif
     549                 :            : }
     550                 :            : 
     551                 :            : static uint8_t
     552                 :        736 : ip_ct_tcp_flags_to_dpif(uint8_t flags)
     553                 :            : {
     554                 :            : #ifdef _WIN32
     555                 :            :     /* Windows currently sends up CT_DPIF_TCP flags */
     556                 :            :     return flags;
     557                 :            : #else
     558                 :        736 :     uint8_t ret = 0;
     559                 :            : #define CT_DPIF_TCP_FLAG(FLAG) \
     560                 :            :         ret |= (flags & IP_CT_TCP_FLAG_##FLAG) ? CT_DPIF_TCPF_##FLAG : 0;
     561                 :        736 :     CT_DPIF_TCP_FLAGS
     562                 :            : #undef CT_DPIF_STATUS_FLAG
     563                 :        736 :     return ret;
     564                 :            : #endif
     565                 :            : }
     566                 :            : 
     567                 :            : static bool
     568                 :        368 : nl_ct_parse_protoinfo_tcp(struct nlattr *nla,
     569                 :            :                           struct ct_dpif_protoinfo *protoinfo)
     570                 :            : {
     571                 :            :     static const struct nl_policy policy[] = {
     572                 :            :         [CTA_PROTOINFO_TCP_STATE] = { .type = NL_A_U8, .optional = false },
     573                 :            :         [CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] = { .type = NL_A_U8,
     574                 :            :                                                 .optional = false },
     575                 :            :         [CTA_PROTOINFO_TCP_WSCALE_REPLY] = { .type = NL_A_U8,
     576                 :            :                                              .optional = false },
     577                 :            :         [CTA_PROTOINFO_TCP_FLAGS_ORIGINAL] = { .type = NL_A_U16,
     578                 :            :                                                .optional = false },
     579                 :            :         [CTA_PROTOINFO_TCP_FLAGS_REPLY] = { .type = NL_A_U16,
     580                 :            :                                             .optional = false },
     581                 :            :     };
     582                 :            :     struct nlattr *attrs[ARRAY_SIZE(policy)];
     583                 :            :     bool parsed;
     584                 :            : 
     585                 :        368 :     parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));
     586                 :            : 
     587         [ +  - ]:        368 :     if (parsed) {
     588                 :            :         const struct nf_ct_tcp_flags *flags_orig, *flags_reply;
     589                 :            :         uint8_t state;
     590                 :        368 :         protoinfo->proto = IPPROTO_TCP;
     591                 :        368 :         state = nl_ct_tcp_state_to_dpif(
     592                 :        368 :             nl_attr_get_u8(attrs[CTA_PROTOINFO_TCP_STATE]));
     593                 :            :         /* The connection tracker keeps only one tcp state for the
     594                 :            :          * connection, but our structures store a separate state for
     595                 :            :          * each endpoint.  Here we duplicate the state. */
     596                 :        368 :         protoinfo->tcp.state_orig = protoinfo->tcp.state_reply = state;
     597                 :        368 :         protoinfo->tcp.wscale_orig = nl_attr_get_u8(
     598                 :        368 :             attrs[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]);
     599                 :        368 :         protoinfo->tcp.wscale_reply = nl_attr_get_u8(
     600                 :        368 :             attrs[CTA_PROTOINFO_TCP_WSCALE_REPLY]);
     601                 :        368 :         flags_orig =
     602                 :        368 :             nl_attr_get_unspec(attrs[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL],
     603                 :            :                                sizeof *flags_orig);
     604                 :        368 :         protoinfo->tcp.flags_orig =
     605                 :        368 :             ip_ct_tcp_flags_to_dpif(flags_orig->flags);
     606                 :        368 :         flags_reply =
     607                 :        368 :             nl_attr_get_unspec(attrs[CTA_PROTOINFO_TCP_FLAGS_REPLY],
     608                 :            :                                sizeof *flags_reply);
     609                 :        368 :         protoinfo->tcp.flags_reply =
     610                 :        368 :             ip_ct_tcp_flags_to_dpif(flags_reply->flags);
     611                 :            :     } else {
     612         [ #  # ]:          0 :         VLOG_ERR_RL(&rl, "Could not parse nested TCP protoinfo options. "
     613                 :            :                     "Possibly incompatible Linux kernel version.");
     614                 :            :     }
     615                 :            : 
     616                 :        368 :     return parsed;
     617                 :            : }
     618                 :            : 
     619                 :            : static bool
     620                 :        368 : nl_ct_parse_protoinfo(struct nlattr *nla, struct ct_dpif_protoinfo *protoinfo)
     621                 :            : {
     622                 :            :     /* These are mutually exclusive. */
     623                 :            :     static const struct nl_policy policy[] = {
     624                 :            :         [CTA_PROTOINFO_TCP] = { .type = NL_A_NESTED, .optional = true },
     625                 :            :         [CTA_PROTOINFO_SCTP] = { .type = NL_A_NESTED, .optional = true },
     626                 :            :     };
     627                 :            :     struct nlattr *attrs[ARRAY_SIZE(policy)];
     628                 :            :     bool parsed;
     629                 :            : 
     630                 :        368 :     parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));
     631                 :            : 
     632                 :        368 :     memset(protoinfo, 0, sizeof *protoinfo);
     633                 :            : 
     634         [ +  - ]:        368 :     if (parsed) {
     635         [ +  - ]:        368 :         if (attrs[CTA_PROTOINFO_TCP]) {
     636                 :        368 :             parsed = nl_ct_parse_protoinfo_tcp(attrs[CTA_PROTOINFO_TCP],
     637                 :            :                                                protoinfo);
     638         [ #  # ]:          0 :         } else if (attrs[CTA_PROTOINFO_SCTP]) {
     639         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "SCTP protoinfo not yet supported!");
     640                 :            :         } else {
     641         [ #  # ]:        368 :             VLOG_WARN_RL(&rl, "Empty protoinfo!");
     642                 :            :         }
     643                 :            :     } else {
     644         [ #  # ]:          0 :         VLOG_ERR_RL(&rl, "Could not parse nested protoinfo options. "
     645                 :            :                     "Possibly incompatible Linux kernel version.");
     646                 :            :     }
     647                 :            : 
     648                 :        368 :     return parsed;
     649                 :            : }
     650                 :            : 
     651                 :            : static bool
     652                 :         14 : nl_ct_parse_helper(struct nlattr *nla, struct ct_dpif_helper *helper)
     653                 :            : {
     654                 :            :     static const struct nl_policy policy[] = {
     655                 :            :         [CTA_HELP_NAME] = { .type = NL_A_STRING, .optional = false },
     656                 :            :     };
     657                 :            :     struct nlattr *attrs[ARRAY_SIZE(policy)];
     658                 :            :     bool parsed;
     659                 :            : 
     660                 :         14 :     parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));
     661                 :            : 
     662                 :         14 :     memset(helper, 0, sizeof *helper);
     663                 :            : 
     664         [ +  - ]:         14 :     if (parsed) {
     665                 :         14 :         helper->name = xstrdup(nl_attr_get_string(attrs[CTA_HELP_NAME]));
     666                 :            :     } else {
     667         [ #  # ]:          0 :         VLOG_ERR_RL(&rl, "Could not parse nested helper options. "
     668                 :            :                     "Possibly incompatible Linux kernel version.");
     669                 :            :     }
     670                 :            : 
     671                 :         14 :     return parsed;
     672                 :            : }
     673                 :            : 
     674                 :            : /* Translate netlink entry status flags to CT_DPIF_TCP status flags. */
     675                 :            : static uint32_t
     676                 :        386 : ips_status_to_dpif_flags(uint32_t status)
     677                 :            : {
     678                 :        386 :     uint32_t ret = 0;
     679                 :            : #define CT_DPIF_STATUS_FLAG(FLAG) \
     680                 :            :         ret |= (status & IPS_##FLAG) ? CT_DPIF_STATUS_##FLAG : 0;
     681                 :        386 :     CT_DPIF_STATUS_FLAGS
     682                 :            : #undef CT_DPIF_STATUS_FLAG
     683                 :        386 :     return ret;
     684                 :            : }
     685                 :            : 
     686                 :            : static bool
     687                 :        386 : nl_ct_parse_header_policy(struct ofpbuf *buf,
     688                 :            :         enum nl_ct_event_type *event_type,
     689                 :            :         uint8_t *nfgen_family,
     690                 :            :         struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)])
     691                 :            : {
     692                 :            :     struct nlmsghdr *nlh;
     693                 :            :     struct nfgenmsg *nfm;
     694                 :            :     uint8_t type;
     695                 :            : 
     696                 :        386 :     nlh = ofpbuf_at(buf, 0, NLMSG_HDRLEN);
     697                 :        386 :     nfm = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *nfm);
     698         [ -  + ]:        386 :     if (!nfm) {
     699         [ #  # ]:          0 :         VLOG_ERR_RL(&rl, "Received bad nfnl message (no nfgenmsg).");
     700                 :          0 :         return false;
     701                 :            :     }
     702         [ -  + ]:        386 :     if (NFNL_SUBSYS_ID(nlh->nlmsg_type) != NFNL_SUBSYS_CTNETLINK) {
     703         [ #  # ]:          0 :         VLOG_ERR_RL(&rl, "Received non-conntrack message (subsystem: %u).",
     704                 :            :                  NFNL_SUBSYS_ID(nlh->nlmsg_type));
     705                 :          0 :         return false;
     706                 :            :     }
     707         [ -  + ]:        386 :     if (nfm->version != NFNETLINK_V0) {
     708         [ #  # ]:          0 :         VLOG_ERR_RL(&rl, "Received unsupported nfnetlink version (%u).",
     709                 :            :                  NFNL_MSG_TYPE(nfm->version));
     710                 :          0 :         return false;
     711                 :            :     }
     712                 :            : 
     713         [ -  + ]:        386 :     if (!nl_policy_parse(buf, NLMSG_HDRLEN + sizeof *nfm,
     714                 :            :                          nfnlgrp_conntrack_policy, attrs,
     715                 :            :                          ARRAY_SIZE(nfnlgrp_conntrack_policy))) {
     716         [ #  # ]:          0 :         VLOG_ERR_RL(&rl, "Received bad nfnl message (policy).");
     717                 :          0 :         return false;
     718                 :            :     }
     719                 :            : 
     720                 :        386 :     type = NFNL_MSG_TYPE(nlh->nlmsg_type);
     721                 :        386 :     *nfgen_family = nfm->nfgen_family;
     722                 :            : 
     723      [ +  -  - ]:        386 :     switch (type) {
     724                 :            :     case IPCTNL_MSG_CT_NEW:
     725         [ -  + ]:        386 :         *event_type = nlh->nlmsg_flags & NLM_F_CREATE
     726                 :            :             ? NL_CT_EVENT_NEW : NL_CT_EVENT_UPDATE;
     727                 :        386 :         break;
     728                 :            :     case IPCTNL_MSG_CT_DELETE:
     729                 :          0 :         *event_type = NL_CT_EVENT_DELETE;
     730                 :          0 :         break;
     731                 :            :     default:
     732         [ #  # ]:          0 :         VLOG_ERR_RL(&rl, "Can't parse conntrack event type.");
     733                 :          0 :         return false;
     734                 :            :     }
     735                 :            : 
     736                 :        386 :     return true;
     737                 :            : }
     738                 :            : 
     739                 :            : static bool
     740                 :        386 : nl_ct_attrs_to_ct_dpif_entry(struct ct_dpif_entry *entry,
     741                 :            :         struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)],
     742                 :            :         uint8_t nfgen_family)
     743                 :            : {
     744         [ -  + ]:        386 :     if (!nl_ct_parse_tuple(attrs[CTA_TUPLE_ORIG], &entry->tuple_orig,
     745                 :            :                            nfgen_family)) {
     746                 :          0 :         return false;
     747                 :            :     }
     748         [ -  + ]:        386 :     if (!nl_ct_parse_tuple(attrs[CTA_TUPLE_REPLY], &entry->tuple_reply,
     749                 :            :                            nfgen_family)) {
     750                 :          0 :         return false;
     751                 :            :     }
     752   [ -  +  #  # ]:        386 :     if (attrs[CTA_COUNTERS_ORIG] &&
     753                 :          0 :         !nl_ct_parse_counters(attrs[CTA_COUNTERS_ORIG],
     754                 :            :                               &entry->counters_orig)) {
     755                 :          0 :         return false;
     756                 :            :     }
     757   [ -  +  #  # ]:        386 :     if (attrs[CTA_COUNTERS_REPLY] &&
     758                 :          0 :         !nl_ct_parse_counters(attrs[CTA_COUNTERS_REPLY],
     759                 :            :                               &entry->counters_reply)) {
     760                 :          0 :         return false;
     761                 :            :     }
     762   [ -  +  #  # ]:        386 :     if (attrs[CTA_TIMESTAMP] &&
     763                 :          0 :         !nl_ct_parse_timestamp(attrs[CTA_TIMESTAMP], &entry->timestamp)) {
     764                 :          0 :         return false;
     765                 :            :     }
     766         [ +  - ]:        386 :     if (attrs[CTA_ID]) {
     767                 :        386 :         entry->id = ntohl(nl_attr_get_be32(attrs[CTA_ID]));
     768                 :            :     }
     769         [ +  + ]:        386 :     if (attrs[CTA_ZONE]) {
     770                 :        294 :         entry->zone = ntohs(nl_attr_get_be16(attrs[CTA_ZONE]));
     771                 :            :     }
     772         [ +  - ]:        386 :     if (attrs[CTA_STATUS]) {
     773                 :        386 :         entry->status = ips_status_to_dpif_flags(
     774                 :        386 :             ntohl(nl_attr_get_be32(attrs[CTA_STATUS])));
     775                 :            :     }
     776         [ +  - ]:        386 :     if (attrs[CTA_TIMEOUT]) {
     777                 :        386 :         entry->timeout = ntohl(nl_attr_get_be32(attrs[CTA_TIMEOUT]));
     778                 :            :     }
     779         [ +  - ]:        386 :     if (attrs[CTA_MARK]) {
     780                 :        386 :         entry->mark = ntohl(nl_attr_get_be32(attrs[CTA_MARK]));
     781                 :            :     }
     782         [ +  + ]:        386 :     if (attrs[CTA_LABELS]) {
     783         [ +  - ]:          2 :         memcpy(&entry->labels, nl_attr_get(attrs[CTA_LABELS]),
     784                 :          2 :                MIN(sizeof entry->labels, nl_attr_get_size(attrs[CTA_LABELS])));
     785                 :            :     }
     786   [ +  +  -  + ]:        754 :     if (attrs[CTA_PROTOINFO] &&
     787                 :        368 :         !nl_ct_parse_protoinfo(attrs[CTA_PROTOINFO], &entry->protoinfo)) {
     788                 :          0 :         return false;
     789                 :            :     }
     790   [ +  +  -  + ]:        400 :     if (attrs[CTA_HELP] &&
     791                 :         14 :         !nl_ct_parse_helper(attrs[CTA_HELP], &entry->helper)) {
     792                 :          0 :         return false;
     793                 :            :     }
     794   [ +  +  -  + ]:        397 :     if (attrs[CTA_TUPLE_MASTER] &&
     795                 :         11 :         !nl_ct_parse_tuple(attrs[CTA_TUPLE_MASTER], &entry->tuple_master,
     796                 :            :                            nfgen_family)) {
     797                 :          0 :         return false;
     798                 :            :     }
     799                 :        386 :     return true;
     800                 :            : }
     801                 :            : 
     802                 :            : bool
     803                 :          0 : nl_ct_parse_entry(struct ofpbuf *buf, struct ct_dpif_entry *entry,
     804                 :            :                   enum nl_ct_event_type *event_type)
     805                 :            : {
     806                 :            :     struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)];
     807                 :            :     uint8_t nfgen_family;
     808                 :            : 
     809                 :          0 :     memset(entry, 0, sizeof *entry);
     810         [ #  # ]:          0 :     if (!nl_ct_parse_header_policy(buf, event_type, &nfgen_family, attrs)) {
     811                 :          0 :         return false;
     812                 :            :     };
     813                 :            : 
     814         [ #  # ]:          0 :     if (!nl_ct_attrs_to_ct_dpif_entry(entry, attrs, nfgen_family)) {
     815                 :          0 :         ct_dpif_entry_uninit(entry);
     816                 :          0 :         memset(entry, 0, sizeof *entry);
     817                 :          0 :         return false;
     818                 :            :     }
     819                 :            : 
     820                 :          0 :     return true;
     821                 :            : }
     822                 :            : 
     823                 :            : /* NetFilter utility functions. */
     824                 :            : 
     825                 :            : /* Puts a nlmsghdr and nfgenmsg at the beginning of 'msg', which must be
     826                 :            :  * initially empty.  'expected_payload' should be an estimate of the number of
     827                 :            :  * payload bytes to be supplied; if the size of the payload is unknown a value
     828                 :            :  * of 0 is acceptable.
     829                 :            :  *
     830                 :            :  * Non-zero 'family' is the address family of items to get (e.g. AF_INET).
     831                 :            :  *
     832                 :            :  * 'flags' is a bit-mask that indicates what kind of request is being made.  It
     833                 :            :  * is often NLM_F_REQUEST indicating that a request is being made, commonly
     834                 :            :  * or'd with NLM_F_ACK to request an acknowledgement.  NLM_F_DUMP flag reguests
     835                 :            :  * a dump of the table.
     836                 :            :  *
     837                 :            :  * 'subsystem' is a netfilter subsystem id, e.g., NFNL_SUBSYS_CTNETLINK.
     838                 :            :  *
     839                 :            :  * 'cmd' is an enumerated value specific to the 'subsystem'.
     840                 :            :  *
     841                 :            :  * Sets the new nlmsghdr's nlmsg_pid field to 0 for now.  nl_sock_send() will
     842                 :            :  * fill it in just before sending the message.
     843                 :            :  *
     844                 :            :  * nl_msg_put_nlmsghdr() should be used to compose Netlink messages that are
     845                 :            :  * not NetFilter Netlink messages. */
     846                 :            : static void
     847                 :        113 : nl_msg_put_nfgenmsg(struct ofpbuf *msg, size_t expected_payload,
     848                 :            :                     int family, uint8_t subsystem, uint8_t cmd,
     849                 :            :                     uint32_t flags)
     850                 :            : {
     851                 :            :     struct nfgenmsg *nfm;
     852                 :            : 
     853                 :        113 :     nl_msg_put_nlmsghdr(msg, sizeof *nfm + expected_payload,
     854                 :        113 :                         subsystem << 8 | cmd, flags);
     855         [ -  + ]:        113 :     ovs_assert(msg->size == NLMSG_HDRLEN);
     856                 :        113 :     nfm = nl_msg_put_uninit(msg, sizeof *nfm);
     857                 :        113 :     nfm->nfgen_family = family;
     858                 :        113 :     nfm->version = NFNETLINK_V0;
     859                 :        113 :     nfm->res_id = 0;
     860                 :            : #ifdef _WIN32
     861                 :            :     /* nfgenmsg contains ovsHdr padding in windows */
     862                 :            :     nfm->ovsHdr.dp_ifindex = 0;
     863                 :            : #endif
     864                 :        113 : }

Generated by: LCOV version 1.12