LCOV - code coverage report
Current view: top level - lib - ct-dpif.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 112 158 70.9 %
Date: 2016-09-14 01:02:56 Functions: 15 19 78.9 %
Branches: 50 97 51.5 %

           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 <errno.h>
      20                 :            : 
      21                 :            : #include "ct-dpif.h"
      22                 :            : 
      23                 :            : #include "dpif-provider.h"
      24                 :            : 
      25                 :            : /* Declarations for conntrack entry formatting. */
      26                 :            : struct flags {
      27                 :            :     uint32_t flag;
      28                 :            :     const char *name;
      29                 :            : };
      30                 :            : 
      31                 :            : static void ct_dpif_format_ipproto(struct ds *, uint16_t ipproto);
      32                 :            : static void ct_dpif_format_counters(struct ds *,
      33                 :            :                                     const struct ct_dpif_counters *);
      34                 :            : static void ct_dpif_format_timestamp(struct ds *,
      35                 :            :                                      const struct ct_dpif_timestamp *);
      36                 :            : static void ct_dpif_format_flags(struct ds *, const char *title,
      37                 :            :                                  uint32_t flags, const struct flags *);
      38                 :            : static void ct_dpif_format_protoinfo(struct ds *, const char *title,
      39                 :            :                                      const struct ct_dpif_protoinfo *,
      40                 :            :                                      bool verbose);
      41                 :            : static void ct_dpif_format_helper(struct ds *, const char *title,
      42                 :            :                                   const struct ct_dpif_helper *);
      43                 :            : 
      44                 :            : static const struct flags ct_dpif_status_flags[] = {
      45                 :            : #define CT_DPIF_STATUS_FLAG(FLAG) { CT_DPIF_STATUS_##FLAG, #FLAG },
      46                 :            :     CT_DPIF_STATUS_FLAGS
      47                 :            : #undef CT_DPIF_STATUS_FLAG
      48                 :            :     { 0, NULL } /* End marker. */
      49                 :            : };
      50                 :            : 
      51                 :            : /* Dumping */
      52                 :            : 
      53                 :            : /* Start dumping the entries from the connection tracker used by 'dpif'.
      54                 :            :  *
      55                 :            :  * 'dump' must be the address of a pointer to a struct ct_dpif_dump_state,
      56                 :            :  * which should be passed (unaltered) to ct_dpif_dump_{next,done}().
      57                 :            :  *
      58                 :            :  * If 'zone' is not NULL, it should point to an integer identifing a
      59                 :            :  * conntrack zone to which the dump will be limited.  If it is NULL,
      60                 :            :  * conntrack entries from all zones will be dumped.
      61                 :            :  *
      62                 :            :  * If there has been a problem the function returns a non-zero value
      63                 :            :  * that represents the error.  Otherwise it returns zero. */
      64                 :            : int
      65                 :         69 : ct_dpif_dump_start(struct dpif *dpif, struct ct_dpif_dump_state **dump,
      66                 :            :                    const uint16_t *zone)
      67                 :            : {
      68                 :            :     int err;
      69                 :            : 
      70                 :        138 :     err = (dpif->dpif_class->ct_dump_start
      71                 :         69 :            ? dpif->dpif_class->ct_dump_start(dpif, dump, zone)
      72         [ +  - ]:         69 :            : EOPNOTSUPP);
      73                 :            : 
      74         [ +  - ]:         69 :     if (!err) {
      75                 :         69 :         (*dump)->dpif = dpif;
      76                 :            :     }
      77                 :            : 
      78                 :         69 :     return err;
      79                 :            : }
      80                 :            : 
      81                 :            : /* Dump one connection from a tracker, and put it in 'entry'.
      82                 :            :  *
      83                 :            :  * 'dump' should have been initialized by ct_dpif_dump_start().
      84                 :            :  *
      85                 :            :  * The function returns 0, if an entry has been dumped succesfully.
      86                 :            :  * Otherwise it returns a non-zero value which can be:
      87                 :            :  * - EOF: meaning that there are no more entries to dump.
      88                 :            :  * - an error value.
      89                 :            :  * In both cases, the user should call ct_dpif_dump_done(). */
      90                 :            : int
      91                 :        503 : ct_dpif_dump_next(struct ct_dpif_dump_state *dump, struct ct_dpif_entry *entry)
      92                 :            : {
      93                 :        503 :     struct dpif *dpif = dump->dpif;
      94                 :            : 
      95                 :        503 :     return (dpif->dpif_class->ct_dump_next
      96                 :        503 :             ? dpif->dpif_class->ct_dump_next(dpif, dump, entry)
      97         [ +  - ]:        503 :             : EOPNOTSUPP);
      98                 :            : }
      99                 :            : 
     100                 :            : /* Free resources used by 'dump' */
     101                 :            : int
     102                 :         69 : ct_dpif_dump_done(struct ct_dpif_dump_state *dump)
     103                 :            : {
     104                 :         69 :     struct dpif *dpif = dump->dpif;
     105                 :            : 
     106                 :         69 :     return (dpif->dpif_class->ct_dump_done
     107                 :         69 :             ? dpif->dpif_class->ct_dump_done(dpif, dump)
     108         [ +  - ]:         69 :             : EOPNOTSUPP);
     109                 :            : }
     110                 :            : 
     111                 :            : /* Flush the entries in the connection tracker used by 'dpif'.
     112                 :            :  *
     113                 :            :  * If 'zone' is not NULL, flush only the entries in '*zone'. */
     114                 :            : int
     115                 :          8 : ct_dpif_flush(struct dpif *dpif, const uint16_t *zone)
     116                 :            : {
     117                 :          8 :     return (dpif->dpif_class->ct_flush
     118                 :          8 :             ? dpif->dpif_class->ct_flush(dpif, zone)
     119         [ +  - ]:          8 :             : EOPNOTSUPP);
     120                 :            : }
     121                 :            : 
     122                 :            : void
     123                 :        434 : ct_dpif_entry_uninit(struct ct_dpif_entry *entry)
     124                 :            : {
     125         [ +  - ]:        434 :     if (entry) {
     126         [ +  + ]:        434 :         if (entry->helper.name) {
     127                 :         14 :             free(entry->helper.name);
     128                 :            :         }
     129                 :            :     }
     130                 :        434 : }
     131                 :            : 
     132                 :            : void
     133                 :        434 : ct_dpif_format_entry(const struct ct_dpif_entry *entry, struct ds *ds,
     134                 :            :                      bool verbose, bool print_stats)
     135                 :            : {
     136                 :        434 :     ct_dpif_format_ipproto(ds, entry->tuple_orig.ip_proto);
     137                 :            : 
     138                 :        434 :     ds_put_cstr(ds, ",orig=(");
     139                 :        434 :     ct_dpif_format_tuple(ds, &entry->tuple_orig);
     140         [ -  + ]:        434 :     if (print_stats) {
     141                 :          0 :         ct_dpif_format_counters(ds, &entry->counters_orig);
     142                 :            :     }
     143                 :        434 :     ds_put_cstr(ds, ")");
     144                 :            : 
     145                 :        434 :     ds_put_cstr(ds, ",reply=(");
     146                 :        434 :     ct_dpif_format_tuple(ds, &entry->tuple_reply);
     147         [ -  + ]:        434 :     if (print_stats) {
     148                 :          0 :         ct_dpif_format_counters(ds, &entry->counters_reply);
     149                 :            :     }
     150                 :        434 :     ds_put_cstr(ds, ")");
     151                 :            : 
     152         [ -  + ]:        434 :     if (print_stats) {
     153                 :          0 :         ct_dpif_format_timestamp(ds, &entry->timestamp);
     154                 :            :     }
     155         [ -  + ]:        434 :     if (verbose) {
     156                 :          0 :         ds_put_format(ds, ",id=%"PRIu32, entry->id);
     157                 :            :     }
     158         [ +  + ]:        434 :     if (entry->zone) {
     159                 :        318 :         ds_put_format(ds, ",zone=%"PRIu16, entry->zone);
     160                 :            :     }
     161         [ -  + ]:        434 :     if (verbose) {
     162                 :          0 :         ct_dpif_format_flags(ds, ",status=", entry->status,
     163                 :            :                              ct_dpif_status_flags);
     164                 :            :     }
     165         [ -  + ]:        434 :     if (print_stats) {
     166                 :          0 :         ds_put_format(ds, ",timeout=%"PRIu32, entry->timeout);
     167                 :            :     }
     168         [ +  + ]:        434 :     if (entry->mark) {
     169                 :         29 :         ds_put_format(ds, ",mark=%"PRIu32, entry->mark);
     170                 :            :     }
     171         [ +  + ]:        434 :     if (!ovs_u128_is_zero(entry->labels)) {
     172                 :            :         ovs_be128 value;
     173                 :            : 
     174                 :          6 :         ds_put_cstr(ds, ",labels=");
     175                 :          6 :         value = hton128(entry->labels);
     176                 :          6 :         ds_put_hex(ds, &value, sizeof value);
     177                 :            :     }
     178                 :        434 :     ct_dpif_format_protoinfo(ds, ",protoinfo=", &entry->protoinfo, verbose);
     179                 :        434 :     ct_dpif_format_helper(ds, ",helper=", &entry->helper);
     180 [ -  + ][ #  # ]:        434 :     if (verbose && entry->tuple_master.l3_type != 0) {
     181                 :          0 :         ds_put_cstr(ds, ",master=(");
     182                 :          0 :         ct_dpif_format_tuple(ds, &entry->tuple_master);
     183                 :          0 :         ds_put_cstr(ds, ")");
     184                 :            :     }
     185                 :        434 : }
     186                 :            : 
     187                 :            : static void
     188                 :        434 : ct_dpif_format_ipproto(struct ds *ds, uint16_t ipproto)
     189                 :            : {
     190                 :            :     const char *name;
     191                 :            : 
     192                 :        434 :     name = (ipproto == IPPROTO_ICMP) ? "icmp"
     193 [ +  + ][ +  + ]:        434 :         : (ipproto == IPPROTO_ICMPV6) ? "icmpv6"
         [ +  + ][ -  + ]
                 [ #  # ]
     194                 :            :         : (ipproto == IPPROTO_TCP) ? "tcp"
     195                 :            :         : (ipproto == IPPROTO_UDP) ? "udp"
     196                 :            :         : (ipproto == IPPROTO_SCTP) ? "sctp"
     197                 :            :         : NULL;
     198                 :            : 
     199         [ +  - ]:        434 :     if (name) {
     200                 :        434 :         ds_put_cstr(ds, name);
     201                 :            :     } else {
     202                 :          0 :         ds_put_format(ds, "%u", ipproto);
     203                 :            :     }
     204                 :        434 : }
     205                 :            : 
     206                 :            : static void
     207                 :          0 : ct_dpif_format_counters(struct ds *ds, const struct ct_dpif_counters *counters)
     208                 :            : {
     209 [ #  # ][ #  # ]:          0 :     if (counters->packets || counters->bytes) {
     210                 :          0 :         ds_put_format(ds, ",packets=%"PRIu64",bytes=%"PRIu64,
     211                 :            :                       counters->packets, counters->bytes);
     212                 :            :     }
     213                 :          0 : }
     214                 :            : 
     215                 :            : static void
     216                 :          0 : ct_dpif_format_timestamp(struct ds *ds,
     217                 :            :                          const struct ct_dpif_timestamp *timestamp)
     218                 :            : {
     219 [ #  # ][ #  # ]:          0 :     if (timestamp->start || timestamp->stop) {
     220                 :          0 :         ds_put_strftime_msec(ds, ",start=%Y-%m-%dT%H:%M:%S.###",
     221                 :          0 :                              timestamp->start / UINT64_C(1000000), false);
     222         [ #  # ]:          0 :         if (timestamp->stop) {
     223                 :          0 :             ds_put_strftime_msec(ds, ",stop=%Y-%m-%dT%H:%M:%S.###",
     224                 :          0 :                                  timestamp->stop / UINT64_C(1000000), false);
     225                 :            :         }
     226                 :            :     }
     227                 :          0 : }
     228                 :            : 
     229                 :            : static void
     230                 :         36 : ct_dpif_format_tuple_icmp(struct ds *ds, const struct ct_dpif_tuple *tuple)
     231                 :            : {
     232                 :         36 :     ds_put_format(ds, ",id=%u,type=%u,code=%u", ntohs(tuple->icmp_id),
     233                 :         72 :                   tuple->icmp_type, tuple->icmp_code);
     234                 :         36 : }
     235                 :            : 
     236                 :            : static void
     237                 :        832 : ct_dpif_format_tuple_tp(struct ds *ds, const struct ct_dpif_tuple *tuple)
     238                 :            : {
     239                 :        832 :     ds_put_format(ds, ",sport=%u,dport=%u",
     240                 :        832 :                   ntohs(tuple->src_port), ntohs(tuple->dst_port));
     241                 :        832 : }
     242                 :            : 
     243                 :            : void
     244                 :        868 : ct_dpif_format_tuple(struct ds *ds, const struct ct_dpif_tuple *tuple)
     245                 :            : {
     246         [ +  + ]:        868 :     if (tuple->l3_type == AF_INET) {
     247                 :        850 :         ds_put_format(ds, "src="IP_FMT",dst="IP_FMT,
     248                 :        850 :                       IP_ARGS(tuple->src.ip), IP_ARGS(tuple->dst.ip));
     249         [ +  - ]:         18 :     } else if (tuple->l3_type == AF_INET6) {
     250                 :         18 :         ds_put_cstr(ds, "src=");
     251                 :         18 :         ipv6_format_addr(&tuple->src.in6, ds);
     252                 :         18 :         ds_put_cstr(ds, ",dst=");
     253                 :         18 :         ipv6_format_addr(&tuple->dst.in6, ds);
     254                 :            :     } else {
     255                 :          0 :         ds_put_format(ds, "Unsupported address family: %u. HEX:\n",
     256                 :          0 :                       tuple->l3_type);
     257                 :          0 :         ds_put_hex_dump(ds, tuple, sizeof *tuple, 0, false);
     258                 :          0 :         return;
     259                 :            :     }
     260                 :            : 
     261         [ +  + ]:        868 :     if (tuple->ip_proto == IPPROTO_ICMP
     262         [ +  + ]:        836 :         || tuple->ip_proto == IPPROTO_ICMPV6) {
     263                 :         36 :         ct_dpif_format_tuple_icmp(ds, tuple);
     264                 :            :     } else {
     265                 :        832 :         ct_dpif_format_tuple_tp(ds, tuple);
     266                 :            :     }
     267                 :            : }
     268                 :            : 
     269                 :            : static void
     270                 :          0 : ct_dpif_format_flags(struct ds *ds, const char *title, uint32_t flags,
     271                 :            :                      const struct flags *table)
     272                 :            : {
     273         [ #  # ]:          0 :     if (title) {
     274                 :          0 :         ds_put_cstr(ds, title);
     275                 :            :     }
     276         [ #  # ]:          0 :     for (; table->name; table++) {
     277         [ #  # ]:          0 :         if (flags & table->flag) {
     278                 :          0 :             ds_put_format(ds, "%s|", table->name);
     279                 :            :         }
     280                 :            :     }
     281                 :          0 :     ds_chomp(ds, '|');
     282                 :          0 : }
     283                 :            : 
     284                 :            : static const struct flags tcp_flags[] = {
     285                 :            : #define CT_DPIF_TCP_FLAG(FLAG)  { CT_DPIF_TCPF_##FLAG, #FLAG },
     286                 :            :     CT_DPIF_TCP_FLAGS
     287                 :            : #undef CT_DPIF_TCP_FLAG
     288                 :            :     { 0, NULL } /* End marker. */
     289                 :            : };
     290                 :            : 
     291                 :            : const char *ct_dpif_tcp_state_string[] = {
     292                 :            : #define CT_DPIF_TCP_STATE(STATE) [CT_DPIF_TCPS_##STATE] = #STATE,
     293                 :            :     CT_DPIF_TCP_STATES
     294                 :            : #undef CT_DPIF_TCP_STATE
     295                 :            : };
     296                 :            : 
     297                 :            : static void
     298                 :        414 : ct_dpif_format_enum__(struct ds *ds, const char *title, unsigned int state,
     299                 :            :                       const char *names[], unsigned int max)
     300                 :            : {
     301         [ +  - ]:        414 :     if (title) {
     302                 :        414 :         ds_put_cstr(ds, title);
     303                 :            :     }
     304         [ +  - ]:        414 :     if (state < max) {
     305                 :        414 :         ds_put_cstr(ds, names[state]);
     306                 :            :     } else {
     307                 :          0 :         ds_put_format(ds, "[%u]", state);
     308                 :            :     }
     309                 :        414 : }
     310                 :            : 
     311                 :            : #define ct_dpif_format_enum(DS, TITLE, STATE, NAMES) \
     312                 :            :     ct_dpif_format_enum__((DS), (TITLE), (STATE), (NAMES), ARRAY_SIZE(NAMES))
     313                 :            : 
     314                 :            : static uint8_t
     315                 :        414 : coalesce_tcp_state(uint8_t state)
     316                 :            : {
     317                 :            :     /* The Linux kernel connection tracker and the userspace view the
     318                 :            :      * tcp states differently in some situations.  If we're formatting
     319                 :            :      * the entry without being verbose, it is worth to adjust the
     320                 :            :      * differences, to ease writing testcases. */
     321      [ +  +  + ]:        414 :     switch (state) {
     322                 :            :         case CT_DPIF_TCPS_FIN_WAIT_2:
     323                 :         16 :             return CT_DPIF_TCPS_TIME_WAIT;
     324                 :            :         case CT_DPIF_TCPS_SYN_RECV:
     325                 :          8 :             return CT_DPIF_TCPS_ESTABLISHED;
     326                 :            :         default:
     327                 :        390 :             return state;
     328                 :            :     }
     329                 :            : }
     330                 :            : 
     331                 :            : static void
     332                 :        414 : ct_dpif_format_protoinfo_tcp(struct ds *ds,
     333                 :            :                              const struct ct_dpif_protoinfo *protoinfo)
     334                 :            : {
     335                 :            :     uint8_t tcp_state;
     336                 :            : 
     337                 :            :     /* We keep two separate tcp states, but we print just one. The Linux
     338                 :            :      * kernel connection tracker internally keeps only one state, so
     339                 :            :      * 'state_orig' and 'state_reply', will be the same. */
     340                 :        414 :     tcp_state = MAX(protoinfo->tcp.state_orig, protoinfo->tcp.state_reply);
     341                 :            : 
     342                 :        414 :     tcp_state = coalesce_tcp_state(tcp_state);
     343                 :        414 :     ct_dpif_format_enum(ds, "state=", tcp_state, ct_dpif_tcp_state_string);
     344                 :        414 : }
     345                 :            : 
     346                 :            : static void
     347                 :          0 : ct_dpif_format_protoinfo_tcp_verbose(struct ds *ds,
     348                 :            :                                      const struct ct_dpif_protoinfo *protoinfo)
     349                 :            : {
     350                 :          0 :     ct_dpif_format_enum(ds, "state_orig=", protoinfo->tcp.state_orig,
     351                 :            :                         ct_dpif_tcp_state_string);
     352                 :          0 :     ct_dpif_format_enum(ds, ",state_reply=", protoinfo->tcp.state_reply,
     353                 :            :                         ct_dpif_tcp_state_string);
     354                 :            : 
     355 [ #  # ][ #  # ]:          0 :     if (protoinfo->tcp.wscale_orig || protoinfo->tcp.wscale_reply) {
     356                 :          0 :         ds_put_format(ds, ",wscale_orig=%u,wscale_reply=%u",
     357                 :          0 :                       protoinfo->tcp.wscale_orig,
     358                 :          0 :                       protoinfo->tcp.wscale_reply);
     359                 :            :     }
     360                 :          0 :     ct_dpif_format_flags(ds, ",flags_orig=", protoinfo->tcp.flags_orig,
     361                 :            :                          tcp_flags);
     362                 :          0 :     ct_dpif_format_flags(ds, ",flags_reply=", protoinfo->tcp.flags_reply,
     363                 :            :                          tcp_flags);
     364                 :          0 : }
     365                 :            : 
     366                 :            : static void
     367                 :        434 : ct_dpif_format_protoinfo(struct ds *ds, const char *title,
     368                 :            :                          const struct ct_dpif_protoinfo *protoinfo,
     369                 :            :                          bool verbose)
     370                 :            : {
     371         [ +  + ]:        434 :     if (protoinfo->proto != 0) {
     372         [ +  - ]:        414 :         if (title) {
     373                 :        414 :             ds_put_format(ds, "%s(", title);
     374                 :            :         }
     375         [ +  - ]:        414 :         switch (protoinfo->proto) {
     376                 :            :         case IPPROTO_TCP:
     377         [ -  + ]:        414 :             if (verbose) {
     378                 :          0 :                 ct_dpif_format_protoinfo_tcp_verbose(ds, protoinfo);
     379                 :            :             } else {
     380                 :        414 :                 ct_dpif_format_protoinfo_tcp(ds, protoinfo);
     381                 :            :             }
     382                 :        414 :             break;
     383                 :            :         }
     384         [ +  - ]:        414 :         if (title) {
     385                 :        414 :             ds_put_cstr(ds, ")");
     386                 :            :         }
     387                 :            :     }
     388                 :        434 : }
     389                 :            : 
     390                 :            : static void
     391                 :        434 : ct_dpif_format_helper(struct ds *ds, const char *title,
     392                 :            :                     const struct ct_dpif_helper *helper)
     393                 :            : {
     394         [ +  + ]:        434 :     if (helper->name) {
     395         [ +  - ]:         14 :         if (title) {
     396                 :         14 :             ds_put_cstr(ds, title);
     397                 :            :         }
     398                 :         14 :         ds_put_cstr(ds, helper->name);
     399                 :            :     }
     400                 :        434 : }

Generated by: LCOV version 1.12