LCOV - code coverage report
Current view: top level - lib - conntrack.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 436 509 85.7 %
Date: 2016-09-14 01:02:56 Functions: 51 53 96.2 %
Branches: 184 286 64.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2015, 2016 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <config.h>
      18                 :            : #include "conntrack.h"
      19                 :            : 
      20                 :            : #include <errno.h>
      21                 :            : #include <sys/types.h>
      22                 :            : #include <netinet/in.h>
      23                 :            : #include <netinet/icmp6.h>
      24                 :            : 
      25                 :            : #include "bitmap.h"
      26                 :            : #include "conntrack-private.h"
      27                 :            : #include "coverage.h"
      28                 :            : #include "csum.h"
      29                 :            : #include "ct-dpif.h"
      30                 :            : #include "dp-packet.h"
      31                 :            : #include "flow.h"
      32                 :            : #include "netdev.h"
      33                 :            : #include "odp-netlink.h"
      34                 :            : #include "openvswitch/hmap.h"
      35                 :            : #include "openvswitch/vlog.h"
      36                 :            : #include "ovs-rcu.h"
      37                 :            : #include "ovs-thread.h"
      38                 :            : #include "poll-loop.h"
      39                 :            : #include "random.h"
      40                 :            : #include "timeval.h"
      41                 :            : 
      42                 :      20190 : VLOG_DEFINE_THIS_MODULE(conntrack);
      43                 :            : 
      44                 :      92814 : COVERAGE_DEFINE(conntrack_full);
      45                 :      92814 : COVERAGE_DEFINE(conntrack_long_cleanup);
      46                 :            : 
      47                 :            : struct conn_lookup_ctx {
      48                 :            :     struct conn_key key;
      49                 :            :     struct conn *conn;
      50                 :            :     uint32_t hash;
      51                 :            :     bool reply;
      52                 :            :     bool related;
      53                 :            : };
      54                 :            : 
      55                 :            : static bool conn_key_extract(struct conntrack *, struct dp_packet *,
      56                 :            :                              ovs_be16 dl_type, struct conn_lookup_ctx *,
      57                 :            :                              uint16_t zone);
      58                 :            : static uint32_t conn_key_hash(const struct conn_key *, uint32_t basis);
      59                 :            : static void conn_key_reverse(struct conn_key *);
      60                 :            : static void conn_key_lookup(struct conntrack_bucket *ctb,
      61                 :            :                             struct conn_lookup_ctx *ctx,
      62                 :            :                             long long now);
      63                 :            : static bool valid_new(struct dp_packet *pkt, struct conn_key *);
      64                 :            : static struct conn *new_conn(struct conntrack_bucket *, struct dp_packet *pkt,
      65                 :            :                              struct conn_key *, long long now);
      66                 :            : static void delete_conn(struct conn *);
      67                 :            : static enum ct_update_res conn_update(struct conn *,
      68                 :            :                                       struct conntrack_bucket *ctb,
      69                 :            :                                       struct dp_packet *, bool reply,
      70                 :            :                                       long long now);
      71                 :            : static bool conn_expired(struct conn *, long long now);
      72                 :            : static void set_mark(struct dp_packet *, struct conn *,
      73                 :            :                      uint32_t val, uint32_t mask);
      74                 :            : static void set_label(struct dp_packet *, struct conn *,
      75                 :            :                       const struct ovs_key_ct_labels *val,
      76                 :            :                       const struct ovs_key_ct_labels *mask);
      77                 :            : static void *clean_thread_main(void *f_);
      78                 :            : 
      79                 :            : static struct ct_l4_proto *l4_protos[] = {
      80                 :            :     [IPPROTO_TCP] = &ct_proto_tcp,
      81                 :            :     [IPPROTO_UDP] = &ct_proto_other,
      82                 :            :     [IPPROTO_ICMP] = &ct_proto_icmp4,
      83                 :            :     [IPPROTO_ICMPV6] = &ct_proto_icmp6,
      84                 :            : };
      85                 :            : 
      86                 :            : long long ct_timeout_val[] = {
      87                 :            : #define CT_TIMEOUT(NAME, VAL) [CT_TM_##NAME] = VAL,
      88                 :            :     CT_TIMEOUTS
      89                 :            : #undef CT_TIMEOUT
      90                 :            : };
      91                 :            : 
      92                 :            : /* If the total number of connections goes above this value, no new connections
      93                 :            :  * are accepted */
      94                 :            : #define DEFAULT_N_CONN_LIMIT 3000000
      95                 :            : 
      96                 :            : /* Initializes the connection tracker 'ct'.  The caller is responsible for
      97                 :            :  * calling 'conntrack_destroy()', when the instance is not needed anymore */
      98                 :            : void
      99                 :        553 : conntrack_init(struct conntrack *ct)
     100                 :            : {
     101                 :            :     unsigned i, j;
     102                 :        553 :     long long now = time_msec();
     103                 :            : 
     104         [ +  + ]:     142121 :     for (i = 0; i < CONNTRACK_BUCKETS; i++) {
     105                 :     141568 :         struct conntrack_bucket *ctb = &ct->buckets[i];
     106                 :            : 
     107                 :     141568 :         ct_lock_init(&ctb->lock);
     108                 :     141568 :         ct_lock_lock(&ctb->lock);
     109                 :     141568 :         hmap_init(&ctb->connections);
     110         [ +  + ]:    1698816 :         for (j = 0; j < ARRAY_SIZE(ctb->exp_lists); j++) {
     111                 :    1557248 :             ovs_list_init(&ctb->exp_lists[j]);
     112                 :            :         }
     113                 :     141568 :         ct_lock_unlock(&ctb->lock);
     114                 :     141568 :         ovs_mutex_init(&ctb->cleanup_mutex);
     115                 :     141568 :         ovs_mutex_lock(&ctb->cleanup_mutex);
     116                 :     141568 :         ctb->next_cleanup = now + CT_TM_MIN;
     117                 :     141568 :         ovs_mutex_unlock(&ctb->cleanup_mutex);
     118                 :            :     }
     119                 :        553 :     ct->hash_basis = random_uint32();
     120                 :        553 :     atomic_count_init(&ct->n_conn, 0);
     121                 :        553 :     atomic_init(&ct->n_conn_limit, DEFAULT_N_CONN_LIMIT);
     122                 :        553 :     latch_init(&ct->clean_thread_exit);
     123                 :        553 :     ct->clean_thread = ovs_thread_create("ct_clean", clean_thread_main, ct);
     124                 :        553 : }
     125                 :            : 
     126                 :            : /* Destroys the connection tracker 'ct' and frees all the allocated memory. */
     127                 :            : void
     128                 :          2 : conntrack_destroy(struct conntrack *ct)
     129                 :            : {
     130                 :            :     unsigned i;
     131                 :            : 
     132                 :          2 :     latch_set(&ct->clean_thread_exit);
     133                 :          2 :     pthread_join(ct->clean_thread, NULL);
     134                 :          2 :     latch_destroy(&ct->clean_thread_exit);
     135         [ +  + ]:        514 :     for (i = 0; i < CONNTRACK_BUCKETS; i++) {
     136                 :        512 :         struct conntrack_bucket *ctb = &ct->buckets[i];
     137                 :            :         struct conn *conn;
     138                 :            : 
     139                 :        512 :         ovs_mutex_destroy(&ctb->cleanup_mutex);
     140                 :        512 :         ct_lock_lock(&ctb->lock);
     141 [ +  - ][ -  + ]:        512 :         HMAP_FOR_EACH_POP(conn, node, &ctb->connections) {
                 [ -  + ]
     142                 :          0 :             atomic_count_dec(&ct->n_conn);
     143                 :          0 :             delete_conn(conn);
     144                 :            :         }
     145                 :        512 :         hmap_destroy(&ctb->connections);
     146                 :        512 :         ct_lock_unlock(&ctb->lock);
     147                 :        512 :         ct_lock_destroy(&ctb->lock);
     148                 :            :     }
     149                 :          2 : }
     150                 :            : 
     151                 :       1390 : static unsigned hash_to_bucket(uint32_t hash)
     152                 :            : {
     153                 :            :     /* Extracts the most significant bits in hash. The least significant bits
     154                 :            :      * are already used internally by the hmap implementation. */
     155                 :            :     BUILD_ASSERT(CONNTRACK_BUCKETS_SHIFT < 32 && CONNTRACK_BUCKETS_SHIFT >= 1);
     156                 :            : 
     157                 :       1390 :     return (hash >> (32 - CONNTRACK_BUCKETS_SHIFT)) % CONNTRACK_BUCKETS;
     158                 :            : }
     159                 :            : 
     160                 :            : static void
     161                 :        624 : write_ct_md(struct dp_packet *pkt, uint16_t state, uint16_t zone,
     162                 :            :             uint32_t mark, ovs_u128 label)
     163                 :            : {
     164                 :        624 :     pkt->md.ct_state = state | CS_TRACKED;
     165                 :        624 :     pkt->md.ct_zone = zone;
     166                 :        624 :     pkt->md.ct_mark = mark;
     167                 :        624 :     pkt->md.ct_label = label;
     168                 :        624 : }
     169                 :            : 
     170                 :            : static struct conn *
     171                 :        146 : conn_not_found(struct conntrack *ct, struct dp_packet *pkt,
     172                 :            :                struct conn_lookup_ctx *ctx, uint16_t *state, bool commit,
     173                 :            :                long long now)
     174                 :            : {
     175                 :        146 :     unsigned bucket = hash_to_bucket(ctx->hash);
     176                 :        146 :     struct conn *nc = NULL;
     177                 :            : 
     178         [ +  + ]:        146 :     if (!valid_new(pkt, &ctx->key)) {
     179                 :          6 :         *state |= CS_INVALID;
     180                 :          6 :         return nc;
     181                 :            :     }
     182                 :            : 
     183                 :        140 :     *state |= CS_NEW;
     184                 :            : 
     185         [ +  + ]:        140 :     if (commit) {
     186                 :            :         unsigned int n_conn_limit;
     187                 :            : 
     188                 :         80 :         atomic_read_relaxed(&ct->n_conn_limit, &n_conn_limit);
     189                 :            : 
     190         [ -  + ]:         80 :         if (atomic_count_get(&ct->n_conn) >= n_conn_limit) {
     191                 :          0 :             COVERAGE_INC(conntrack_full);
     192                 :          0 :             return nc;
     193                 :            :         }
     194                 :            : 
     195                 :         80 :         nc = new_conn(&ct->buckets[bucket], pkt, &ctx->key, now);
     196                 :            : 
     197                 :         80 :         memcpy(&nc->rev_key, &ctx->key, sizeof nc->rev_key);
     198                 :            : 
     199                 :         80 :         conn_key_reverse(&nc->rev_key);
     200                 :         80 :         hmap_insert(&ct->buckets[bucket].connections, &nc->node, ctx->hash);
     201                 :         80 :         atomic_count_inc(&ct->n_conn);
     202                 :            :     }
     203                 :            : 
     204                 :        140 :     return nc;
     205                 :            : }
     206                 :            : 
     207                 :            : static struct conn *
     208                 :        622 : process_one(struct conntrack *ct, struct dp_packet *pkt,
     209                 :            :             struct conn_lookup_ctx *ctx, uint16_t zone,
     210                 :            :             bool commit, long long now)
     211                 :            : {
     212                 :        622 :     unsigned bucket = hash_to_bucket(ctx->hash);
     213                 :        622 :     struct conn *conn = ctx->conn;
     214                 :        622 :     uint16_t state = 0;
     215                 :            : 
     216         [ +  + ]:        622 :     if (conn) {
     217         [ +  + ]:        477 :         if (ctx->related) {
     218                 :          3 :             state |= CS_RELATED;
     219         [ +  - ]:          3 :             if (ctx->reply) {
     220                 :          3 :                 state |= CS_REPLY_DIR;
     221                 :            :             }
     222                 :            :         } else {
     223                 :            :             enum ct_update_res res;
     224                 :            : 
     225                 :        474 :             res = conn_update(conn, &ct->buckets[bucket], pkt,
     226                 :        474 :                               ctx->reply, now);
     227                 :            : 
     228   [ +  -  +  - ]:        474 :             switch (res) {
     229                 :            :             case CT_UPDATE_VALID:
     230                 :        473 :                 state |= CS_ESTABLISHED;
     231         [ +  + ]:        473 :                 if (ctx->reply) {
     232                 :        264 :                     state |= CS_REPLY_DIR;
     233                 :            :                 }
     234                 :        473 :                 break;
     235                 :            :             case CT_UPDATE_INVALID:
     236                 :          0 :                 state |= CS_INVALID;
     237                 :          0 :                 break;
     238                 :            :             case CT_UPDATE_NEW:
     239                 :          1 :                 ovs_list_remove(&conn->exp_node);
     240                 :          1 :                 hmap_remove(&ct->buckets[bucket].connections, &conn->node);
     241                 :          1 :                 atomic_count_dec(&ct->n_conn);
     242                 :          1 :                 delete_conn(conn);
     243                 :          1 :                 conn = conn_not_found(ct, pkt, ctx, &state, commit, now);
     244                 :        477 :                 break;
     245                 :            :             default:
     246                 :          0 :                 OVS_NOT_REACHED();
     247                 :            :             }
     248                 :            :         }
     249                 :            :     } else {
     250                 :        145 :         conn = conn_not_found(ct, pkt, ctx, &state, commit, now);
     251                 :            :     }
     252                 :            : 
     253 [ +  + ][ +  + ]:        622 :     write_ct_md(pkt, state, zone, conn ? conn->mark : 0,
     254                 :            :                 conn ? conn->label : OVS_U128_ZERO);
     255                 :            : 
     256                 :        622 :     return conn;
     257                 :            : }
     258                 :            : 
     259                 :            : /* Sends the packets in '*pkt_batch' through the connection tracker 'ct'.  All
     260                 :            :  * the packets should have the same 'dl_type' (IPv4 or IPv6) and should have
     261                 :            :  * the l3 and and l4 offset properly set.
     262                 :            :  *
     263                 :            :  * If 'commit' is true, the packets are allowed to create new entries in the
     264                 :            :  * connection tables.  'setmark', if not NULL, should point to a two
     265                 :            :  * elements array containing a value and a mask to set the connection mark.
     266                 :            :  * 'setlabel' behaves similarly for the connection label.*/
     267                 :            : int
     268                 :        624 : conntrack_execute(struct conntrack *ct, struct dp_packet_batch *pkt_batch,
     269                 :            :                   ovs_be16 dl_type, bool commit, uint16_t zone,
     270                 :            :                   const uint32_t *setmark,
     271                 :            :                   const struct ovs_key_ct_labels *setlabel,
     272                 :            :                   const char *helper)
     273                 :        624 : {
     274                 :        624 :     struct dp_packet **pkts = pkt_batch->packets;
     275                 :        624 :     size_t cnt = pkt_batch->count;
     276                 :            : #if !defined(__CHECKER__) && !defined(_WIN32)
     277                 :        624 :     const size_t KEY_ARRAY_SIZE = cnt;
     278                 :            : #else
     279                 :            :     enum { KEY_ARRAY_SIZE = NETDEV_MAX_BURST };
     280                 :            : #endif
     281                 :        624 :     struct conn_lookup_ctx ctxs[KEY_ARRAY_SIZE];
     282                 :            :     int8_t bucket_list[CONNTRACK_BUCKETS];
     283                 :            :     struct {
     284                 :            :         unsigned bucket;
     285                 :            :         unsigned long maps;
     286                 :        624 :     } arr[KEY_ARRAY_SIZE];
     287                 :        624 :     long long now = time_msec();
     288                 :        624 :     size_t i = 0;
     289                 :        624 :     uint8_t arrcnt = 0;
     290                 :            : 
     291                 :            :     BUILD_ASSERT_DECL(sizeof arr[0].maps * CHAR_BIT >= NETDEV_MAX_BURST);
     292                 :            : 
     293         [ -  + ]:        624 :     if (helper) {
     294                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
     295                 :            : 
     296         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "ALG helper \"%s\" not supported", helper);
     297                 :            :         /* Continue without the helper */
     298                 :            :     }
     299                 :            : 
     300                 :        624 :     memset(bucket_list, INT8_C(-1), sizeof bucket_list);
     301         [ +  + ]:       1248 :     for (i = 0; i < cnt; i++) {
     302                 :            :         unsigned bucket;
     303                 :            : 
     304         [ +  + ]:        624 :         if (!conn_key_extract(ct, pkts[i], dl_type, &ctxs[i], zone)) {
     305                 :          2 :             write_ct_md(pkts[i], CS_INVALID, zone, 0, OVS_U128_ZERO);
     306                 :          2 :             continue;
     307                 :            :         }
     308                 :            : 
     309                 :        622 :         bucket = hash_to_bucket(ctxs[i].hash);
     310         [ +  - ]:        622 :         if (bucket_list[bucket] == INT8_C(-1)) {
     311                 :        622 :             bucket_list[bucket] = arrcnt;
     312                 :            : 
     313                 :        622 :             arr[arrcnt].maps = 0;
     314                 :        622 :             ULLONG_SET1(arr[arrcnt].maps, i);
     315                 :        622 :             arr[arrcnt++].bucket = bucket;
     316                 :            :         } else {
     317                 :          0 :             ULLONG_SET1(arr[bucket_list[bucket]].maps, i);
     318                 :          0 :             arr[bucket_list[bucket]].maps |= 1UL << i;
     319                 :            :         }
     320                 :            :     }
     321                 :            : 
     322         [ +  + ]:       1246 :     for (i = 0; i < arrcnt; i++) {
     323                 :        622 :         struct conntrack_bucket *ctb = &ct->buckets[arr[i].bucket];
     324                 :            :         size_t j;
     325                 :            : 
     326                 :        622 :         ct_lock_lock(&ctb->lock);
     327                 :            : 
     328         [ +  + ]:       1244 :         ULLONG_FOR_EACH_1(j, arr[i].maps) {
     329                 :            :             struct conn *conn;
     330                 :            : 
     331                 :        622 :             conn_key_lookup(ctb, &ctxs[j], now);
     332                 :            : 
     333                 :        622 :             conn = process_one(ct, pkts[j], &ctxs[j], zone, commit, now);
     334                 :            : 
     335 [ +  + ][ +  + ]:        622 :             if (conn && setmark) {
     336                 :         50 :                 set_mark(pkts[j], conn, setmark[0], setmark[1]);
     337                 :            :             }
     338                 :            : 
     339 [ +  + ][ +  + ]:        622 :             if (conn && setlabel) {
     340                 :         44 :                 set_label(pkts[j], conn, &setlabel[0], &setlabel[1]);
     341                 :            :             }
     342                 :            :         }
     343                 :        622 :         ct_lock_unlock(&ctb->lock);
     344                 :            :     }
     345                 :            : 
     346                 :        624 :     return 0;
     347                 :            : }
     348                 :            : 
     349                 :            : static void
     350                 :         50 : set_mark(struct dp_packet *pkt, struct conn *conn, uint32_t val, uint32_t mask)
     351                 :            : {
     352                 :         50 :     pkt->md.ct_mark = val | (pkt->md.ct_mark & ~(mask));
     353                 :         50 :     conn->mark = pkt->md.ct_mark;
     354                 :         50 : }
     355                 :            : 
     356                 :            : static void
     357                 :         44 : set_label(struct dp_packet *pkt, struct conn *conn,
     358                 :            :           const struct ovs_key_ct_labels *val,
     359                 :            :           const struct ovs_key_ct_labels *mask)
     360                 :            : {
     361                 :            :     ovs_u128 v, m;
     362                 :            : 
     363                 :         44 :     memcpy(&v, val, sizeof v);
     364                 :         44 :     memcpy(&m, mask, sizeof m);
     365                 :            : 
     366                 :         88 :     pkt->md.ct_label.u64.lo = v.u64.lo
     367                 :         44 :                               | (pkt->md.ct_label.u64.lo & ~(m.u64.lo));
     368                 :         88 :     pkt->md.ct_label.u64.hi = v.u64.hi
     369                 :         44 :                               | (pkt->md.ct_label.u64.hi & ~(m.u64.hi));
     370                 :         44 :     conn->label = pkt->md.ct_label;
     371                 :         44 : }
     372                 :            : 
     373                 :            : /* Delete the expired connections from 'ctb', up to 'limit'. Returns the
     374                 :            :  * earliest expiration time among the remaining connections in 'ctb'.  Returns
     375                 :            :  * LLONG_MAX if 'ctb' is empty.  The return value might be smaller than 'now',
     376                 :            :  * if 'limit' is reached */
     377                 :            : static long long
     378                 :      16896 : sweep_bucket(struct conntrack *ct, struct conntrack_bucket *ctb, long long now,
     379                 :            :              size_t limit)
     380                 :            :     OVS_REQUIRES(ctb->lock)
     381                 :            : {
     382                 :            :     struct conn *conn, *next;
     383                 :      16896 :     long long min_expiration = LLONG_MAX;
     384                 :            :     unsigned i;
     385                 :      16896 :     size_t count = 0;
     386                 :            : 
     387         [ +  + ]:     202752 :     for (i = 0; i < N_CT_TM; i++) {
     388 [ +  + ][ +  + ]:     185857 :         LIST_FOR_EACH_SAFE (conn, next, exp_node, &ctb->exp_lists[i]) {
     389 [ +  - ][ -  + ]:          1 :             if (!conn_expired(conn, now) || count >= limit) {
     390                 :          0 :                 min_expiration = MIN(min_expiration, conn->expiration);
     391         [ #  # ]:          0 :                 if (count >= limit) {
     392                 :            :                     /* Do not check other lists. */
     393                 :          0 :                     COVERAGE_INC(conntrack_long_cleanup);
     394                 :          0 :                     return min_expiration;
     395                 :            :                 }
     396                 :          0 :                 break;
     397                 :            :             }
     398                 :          1 :             ovs_list_remove(&conn->exp_node);
     399                 :          1 :             hmap_remove(&ctb->connections, &conn->node);
     400                 :          1 :             atomic_count_dec(&ct->n_conn);
     401                 :          1 :             delete_conn(conn);
     402                 :          1 :             count++;
     403                 :            :         }
     404                 :            :     }
     405                 :            : 
     406                 :      16896 :     return min_expiration;
     407                 :            : }
     408                 :            : 
     409                 :            : /* Cleans up old connection entries from 'ct'.  Returns the time when the
     410                 :            :  * next expiration might happen.  The return value might be smaller than
     411                 :            :  * 'now', meaning that an internal limit has been reached, and some expired
     412                 :            :  * connections have not been deleted. */
     413                 :            : static long long
     414                 :       5853 : conntrack_clean(struct conntrack *ct, long long now)
     415                 :            : {
     416                 :       5853 :     long long next_wakeup = now + CT_TM_MIN;
     417                 :            :     unsigned int n_conn_limit;
     418                 :       5853 :     size_t clean_count = 0;
     419                 :            :     unsigned i;
     420                 :            : 
     421                 :       5853 :     atomic_read_relaxed(&ct->n_conn_limit, &n_conn_limit);
     422                 :            : 
     423         [ +  + ]:    1504221 :     for (i = 0; i < CONNTRACK_BUCKETS; i++) {
     424                 :    1498368 :         struct conntrack_bucket *ctb = &ct->buckets[i];
     425                 :            :         size_t prev_count;
     426                 :            :         long long min_exp;
     427                 :            : 
     428                 :    1498368 :         ovs_mutex_lock(&ctb->cleanup_mutex);
     429         [ +  + ]:    1498368 :         if (ctb->next_cleanup > now) {
     430                 :    1481472 :             goto next_bucket;
     431                 :            :         }
     432                 :            : 
     433                 :      16896 :         ct_lock_lock(&ctb->lock);
     434                 :      16896 :         prev_count = hmap_count(&ctb->connections);
     435                 :            :         /* If the connections are well distributed among buckets, we want to
     436                 :            :          * limit to 10% of the global limit equally split among buckets. If
     437                 :            :          * the bucket is busier than the others, we limit to 10% of its
     438                 :            :          * current size. */
     439                 :      16896 :         min_exp = sweep_bucket(ct, ctb, now,
     440                 :      33792 :                 MAX(prev_count/10, n_conn_limit/(CONNTRACK_BUCKETS*10)));
     441                 :      16896 :         clean_count += prev_count - hmap_count(&ctb->connections);
     442                 :            : 
     443         [ +  - ]:      16896 :         if (min_exp > now) {
     444                 :            :             /* We call hmap_shrink() only if sweep_bucket() managed to delete
     445                 :            :              * every expired connection. */
     446                 :      16896 :             hmap_shrink(&ctb->connections);
     447                 :            :         }
     448                 :            : 
     449                 :      16896 :         ct_lock_unlock(&ctb->lock);
     450                 :            : 
     451                 :      16896 :         ctb->next_cleanup = MIN(min_exp, now + CT_TM_MIN);
     452                 :            : 
     453                 :            : next_bucket:
     454                 :    1498368 :         next_wakeup = MIN(next_wakeup, ctb->next_cleanup);
     455                 :    1498368 :         ovs_mutex_unlock(&ctb->cleanup_mutex);
     456                 :            :     }
     457                 :            : 
     458         [ -  + ]:       5853 :     VLOG_DBG("conntrack cleanup %"PRIuSIZE" entries in %lld msec",
     459                 :            :              clean_count, time_msec() - now);
     460                 :            : 
     461                 :       5853 :     return next_wakeup;
     462                 :            : }
     463                 :            : 
     464                 :            : /* Cleanup:
     465                 :            :  *
     466                 :            :  * We must call conntrack_clean() periodically.  conntrack_clean() return
     467                 :            :  * value gives an hint on when the next cleanup must be done (either because
     468                 :            :  * there is an actual connection that expires, or because a new connection
     469                 :            :  * might be created with the minimum timeout).
     470                 :            :  *
     471                 :            :  * The logic below has two goals:
     472                 :            :  *
     473                 :            :  * - We want to reduce the number of wakeups and batch connection cleanup
     474                 :            :  *   when the load is not very high.  CT_CLEAN_INTERVAL ensures that if we
     475                 :            :  *   are coping with the current cleanup tasks, then we wait at least
     476                 :            :  *   5 seconds to do further cleanup.
     477                 :            :  *
     478                 :            :  * - We don't want to keep the buckets locked too long, as we might prevent
     479                 :            :  *   traffic from flowing.  CT_CLEAN_MIN_INTERVAL ensures that if cleanup is
     480                 :            :  *   behind, there is at least some 200ms blocks of time when buckets will be
     481                 :            :  *   left alone, so the datapath can operate unhindered.
     482                 :            :  */
     483                 :            : #define CT_CLEAN_INTERVAL 5000 /* 5 seconds */
     484                 :            : #define CT_CLEAN_MIN_INTERVAL 200  /* 0.2 seconds */
     485                 :            : 
     486                 :            : static void *
     487                 :        553 : clean_thread_main(void *f_)
     488                 :            : {
     489                 :        553 :     struct conntrack *ct = f_;
     490                 :            : 
     491         [ +  + ]:       5855 :     while (!latch_is_set(&ct->clean_thread_exit)) {
     492                 :            :         long long next_wake;
     493                 :       5853 :         long long now = time_msec();
     494                 :            : 
     495                 :       5853 :         next_wake = conntrack_clean(ct, now);
     496                 :            : 
     497         [ -  + ]:       5853 :         if (next_wake < now) {
     498                 :          0 :             poll_timer_wait_until(now + CT_CLEAN_MIN_INTERVAL);
     499                 :            :         } else {
     500                 :       5853 :             poll_timer_wait_until(MAX(next_wake, now + CT_CLEAN_INTERVAL));
     501                 :            :         }
     502                 :       5853 :         latch_wait(&ct->clean_thread_exit);
     503                 :       5853 :         poll_block();
     504                 :            :     }
     505                 :            : 
     506                 :          2 :     return NULL;
     507                 :            : }
     508                 :            : 
     509                 :            : /* Key extraction */
     510                 :            : 
     511                 :            : /* The function stores a pointer to the first byte after the header in
     512                 :            :  * '*new_data', if 'new_data' is not NULL.  If it is NULL, the caller is
     513                 :            :  * not interested in the header's tail,  meaning that the header has
     514                 :            :  * already been parsed (e.g. by flow_extract): we take this as a hint to
     515                 :            :  * save a few checks.  If 'validate_checksum' is true, the function returns
     516                 :            :  * false if the IPv4 checksum is invalid. */
     517                 :            : static inline bool
     518                 :        582 : extract_l3_ipv4(struct conn_key *key, const void *data, size_t size,
     519                 :            :                 const char **new_data, bool validate_checksum)
     520                 :            : {
     521                 :        582 :     const struct ip_header *ip = data;
     522                 :            :     size_t ip_len;
     523                 :            : 
     524         [ +  + ]:        582 :     if (new_data) {
     525         [ -  + ]:          4 :         if (OVS_UNLIKELY(size < IP_HEADER_LEN)) {
     526                 :          0 :             return false;
     527                 :            :         }
     528                 :            :     }
     529                 :            : 
     530                 :        582 :     ip_len = IP_IHL(ip->ip_ihl_ver) * 4;
     531                 :            : 
     532         [ +  + ]:        582 :     if (new_data) {
     533         [ -  + ]:          4 :         if (OVS_UNLIKELY(ip_len < IP_HEADER_LEN)) {
     534                 :          0 :             return false;
     535                 :            :         }
     536         [ -  + ]:          4 :         if (OVS_UNLIKELY(size < ip_len)) {
     537                 :          0 :             return false;
     538                 :            :         }
     539                 :            : 
     540                 :          4 :         *new_data = (char *) data + ip_len;
     541                 :            :     }
     542                 :            : 
     543         [ -  + ]:        582 :     if (IP_IS_FRAGMENT(ip->ip_frag_off)) {
     544                 :          0 :         return false;
     545                 :            :     }
     546                 :            : 
     547 [ +  + ][ +  + ]:        582 :     if (validate_checksum && csum(data, ip_len) != 0) {
     548                 :          1 :         return false;
     549                 :            :     }
     550                 :            : 
     551                 :        581 :     key->src.addr.ipv4 = ip->ip_src;
     552                 :        581 :     key->dst.addr.ipv4 = ip->ip_dst;
     553                 :        581 :     key->nw_proto = ip->ip_proto;
     554                 :            : 
     555                 :        581 :     return true;
     556                 :            : }
     557                 :            : 
     558                 :            : /* The function stores a pointer to the first byte after the header in
     559                 :            :  * '*new_data', if 'new_data' is not NULL.  If it is NULL, the caller is
     560                 :            :  * not interested in the header's tail,  meaning that the header has
     561                 :            :  * already been parsed (e.g. by flow_extract): we take this as a hint to
     562                 :            :  * save a few checks. */
     563                 :            : static inline bool
     564                 :         45 : extract_l3_ipv6(struct conn_key *key, const void *data, size_t size,
     565                 :            :                 const char **new_data)
     566                 :            : {
     567                 :         45 :     const struct ovs_16aligned_ip6_hdr *ip6 = data;
     568                 :         45 :     uint8_t nw_proto = ip6->ip6_nxt;
     569                 :         45 :     uint8_t nw_frag = 0;
     570                 :            : 
     571         [ -  + ]:         45 :     if (new_data) {
     572         [ #  # ]:          0 :         if (OVS_UNLIKELY(size < sizeof *ip6)) {
     573                 :          0 :             return false;
     574                 :            :         }
     575                 :            :     }
     576                 :            : 
     577                 :         45 :     data = ip6 + 1;
     578                 :         45 :     size -=  sizeof *ip6;
     579                 :            : 
     580         [ -  + ]:         45 :     if (!parse_ipv6_ext_hdrs(&data, &size, &nw_proto, &nw_frag)) {
     581                 :          0 :         return false;
     582                 :            :     }
     583                 :            : 
     584         [ -  + ]:         45 :     if (new_data) {
     585                 :          0 :         *new_data = data;
     586                 :            :     }
     587                 :            : 
     588         [ -  + ]:         45 :     if (nw_frag) {
     589                 :          0 :         return false;
     590                 :            :     }
     591                 :            : 
     592                 :         45 :     key->src.addr.ipv6 = ip6->ip6_src;
     593                 :         45 :     key->dst.addr.ipv6 = ip6->ip6_dst;
     594                 :         45 :     key->nw_proto = nw_proto;
     595                 :            : 
     596                 :         45 :     return true;
     597                 :            : }
     598                 :            : 
     599                 :            : static inline bool
     600                 :        600 : checksum_valid(const struct conn_key *key, const void *data, size_t size,
     601                 :            :                const void *l3)
     602                 :            : {
     603                 :        600 :     uint32_t csum = 0;
     604                 :            : 
     605         [ +  + ]:        600 :     if (key->dl_type == htons(ETH_TYPE_IP)) {
     606                 :        555 :         csum = packet_csum_pseudoheader(l3);
     607         [ +  - ]:         45 :     } else if (key->dl_type == htons(ETH_TYPE_IPV6)) {
     608                 :         45 :         csum = packet_csum_pseudoheader6(l3);
     609                 :            :     } else {
     610                 :          0 :         return false;
     611                 :            :     }
     612                 :            : 
     613                 :        600 :     csum = csum_continue(csum, data, size);
     614                 :            : 
     615                 :        600 :     return csum_finish(csum) == 0;
     616                 :            : }
     617                 :            : 
     618                 :            : static inline bool
     619                 :        543 : check_l4_tcp(const struct conn_key *key, const void *data, size_t size,
     620                 :            :              const void *l3)
     621                 :            : {
     622                 :        543 :     const struct tcp_header *tcp = data;
     623                 :        543 :     size_t tcp_len = TCP_OFFSET(tcp->tcp_ctl) * 4;
     624                 :            : 
     625 [ +  - ][ -  + ]:        543 :     if (OVS_UNLIKELY(tcp_len < TCP_HEADER_LEN || tcp_len > size)) {
     626                 :          0 :         return false;
     627                 :            :     }
     628                 :            : 
     629                 :        543 :     return checksum_valid(key, data, size, l3);
     630                 :            : }
     631                 :            : 
     632                 :            : static inline bool
     633                 :         45 : check_l4_udp(const struct conn_key *key, const void *data, size_t size,
     634                 :            :              const void *l3)
     635                 :            : {
     636                 :         45 :     const struct udp_header *udp = data;
     637                 :         45 :     size_t udp_len = ntohs(udp->udp_len);
     638                 :            : 
     639 [ +  - ][ -  + ]:         45 :     if (OVS_UNLIKELY(udp_len < UDP_HEADER_LEN || udp_len > size)) {
     640                 :          0 :         return false;
     641                 :            :     }
     642                 :            : 
     643                 :            :     /* Validation must be skipped if checksum is 0 on IPv4 packets */
     644         [ -  + ]:         48 :     return (udp->udp_csum == 0 && key->dl_type == htons(ETH_TYPE_IP))
     645 [ +  + ][ +  - ]:         48 :            || checksum_valid(key, data, size, l3);
     646                 :            : }
     647                 :            : 
     648                 :            : static inline bool
     649                 :         19 : check_l4_icmp(const void *data, size_t size)
     650                 :            : {
     651                 :         19 :     return csum(data, size) == 0;
     652                 :            : }
     653                 :            : 
     654                 :            : static inline bool
     655                 :         15 : check_l4_icmp6(const struct conn_key *key, const void *data, size_t size,
     656                 :            :                const void *l3)
     657                 :            : {
     658                 :         15 :     return checksum_valid(key, data, size, l3);
     659                 :            : }
     660                 :            : 
     661                 :            : static inline bool
     662                 :        543 : extract_l4_tcp(struct conn_key *key, const void *data, size_t size)
     663                 :            : {
     664                 :        543 :     const struct tcp_header *tcp = data;
     665                 :            : 
     666         [ -  + ]:        543 :     if (OVS_UNLIKELY(size < TCP_HEADER_LEN)) {
     667                 :          0 :         return false;
     668                 :            :     }
     669                 :            : 
     670                 :        543 :     key->src.port = tcp->tcp_src;
     671                 :        543 :     key->dst.port = tcp->tcp_dst;
     672                 :            : 
     673                 :            :     /* Port 0 is invalid */
     674 [ +  - ][ +  - ]:        543 :     return key->src.port && key->dst.port;
     675                 :            : }
     676                 :            : 
     677                 :            : static inline bool
     678                 :         49 : extract_l4_udp(struct conn_key *key, const void *data, size_t size)
     679                 :            : {
     680                 :         49 :     const struct udp_header *udp = data;
     681                 :            : 
     682         [ -  + ]:         49 :     if (OVS_UNLIKELY(size < UDP_HEADER_LEN)) {
     683                 :          0 :         return false;
     684                 :            :     }
     685                 :            : 
     686                 :         49 :     key->src.port = udp->udp_src;
     687                 :         49 :     key->dst.port = udp->udp_dst;
     688                 :            : 
     689                 :            :     /* Port 0 is invalid */
     690 [ +  - ][ +  - ]:         49 :     return key->src.port && key->dst.port;
     691                 :            : }
     692                 :            : 
     693                 :            : static inline bool extract_l4(struct conn_key *key, const void *data,
     694                 :            :                               size_t size, bool *related, const void *l3);
     695                 :            : 
     696                 :            : static uint8_t
     697                 :         15 : reverse_icmp_type(uint8_t type)
     698                 :            : {
     699   [ +  +  -  -  :         15 :     switch (type) {
                -  -  - ]
     700                 :            :     case ICMP4_ECHO_REQUEST:
     701                 :         12 :         return ICMP4_ECHO_REPLY;
     702                 :            :     case ICMP4_ECHO_REPLY:
     703                 :          3 :         return ICMP4_ECHO_REQUEST;
     704                 :            : 
     705                 :            :     case ICMP4_TIMESTAMP:
     706                 :          0 :         return ICMP4_TIMESTAMPREPLY;
     707                 :            :     case ICMP4_TIMESTAMPREPLY:
     708                 :          0 :         return ICMP4_TIMESTAMP;
     709                 :            : 
     710                 :            :     case ICMP4_INFOREQUEST:
     711                 :          0 :         return ICMP4_INFOREPLY;
     712                 :            :     case ICMP4_INFOREPLY:
     713                 :          0 :         return ICMP4_INFOREQUEST;
     714                 :            :     default:
     715                 :          0 :         OVS_NOT_REACHED();
     716                 :            :     }
     717                 :            : }
     718                 :            : 
     719                 :            : /* If 'related' is not NULL and the function is processing an ICMP
     720                 :            :  * error packet, extract the l3 and l4 fields from the nested header
     721                 :            :  * instead and set *related to true.  If 'related' is NULL we're
     722                 :            :  * already processing a nested header and no such recursion is
     723                 :            :  * possible */
     724                 :            : static inline int
     725                 :         19 : extract_l4_icmp(struct conn_key *key, const void *data, size_t size,
     726                 :            :                 bool *related)
     727                 :            : {
     728                 :         19 :     const struct icmp_header *icmp = data;
     729                 :            : 
     730         [ -  + ]:         19 :     if (OVS_UNLIKELY(size < ICMP_HEADER_LEN)) {
     731                 :          0 :         return false;
     732                 :            :     }
     733                 :            : 
     734      [ +  +  - ]:         19 :     switch (icmp->icmp_type) {
     735                 :            :     case ICMP4_ECHO_REQUEST:
     736                 :            :     case ICMP4_ECHO_REPLY:
     737                 :            :     case ICMP4_TIMESTAMP:
     738                 :            :     case ICMP4_TIMESTAMPREPLY:
     739                 :            :     case ICMP4_INFOREQUEST:
     740                 :            :     case ICMP4_INFOREPLY:
     741         [ -  + ]:         15 :         if (icmp->icmp_code != 0) {
     742                 :          0 :             return false;
     743                 :            :         }
     744                 :            :         /* Separate ICMP connection: identified using id */
     745                 :         15 :         key->src.icmp_id = key->dst.icmp_id = icmp->icmp_fields.echo.id;
     746                 :         15 :         key->src.icmp_type = icmp->icmp_type;
     747                 :         15 :         key->dst.icmp_type = reverse_icmp_type(icmp->icmp_type);
     748                 :         15 :         break;
     749                 :            :     case ICMP4_DST_UNREACH:
     750                 :            :     case ICMP4_TIME_EXCEEDED:
     751                 :            :     case ICMP4_PARAM_PROB:
     752                 :            :     case ICMP4_SOURCEQUENCH:
     753                 :            :     case ICMP4_REDIRECT: {
     754                 :            :         /* ICMP packet part of another connection. We should
     755                 :            :          * extract the key from embedded packet header */
     756                 :            :         struct conn_key inner_key;
     757                 :          4 :         const char *l3 = (const char *) (icmp + 1);
     758                 :          4 :         const char *tail = (const char *) data + size;
     759                 :            :         const char *l4;
     760                 :            :         bool ok;
     761                 :            : 
     762         [ -  + ]:          4 :         if (!related) {
     763                 :          0 :             return false;
     764                 :            :         }
     765                 :            : 
     766                 :          4 :         memset(&inner_key, 0, sizeof inner_key);
     767                 :          4 :         inner_key.dl_type = htons(ETH_TYPE_IP);
     768                 :          4 :         ok = extract_l3_ipv4(&inner_key, l3, tail - l3, &l4, false);
     769         [ -  + ]:          4 :         if (!ok) {
     770                 :          0 :             return false;
     771                 :            :         }
     772                 :            : 
     773                 :            :         /* pf doesn't do this, but it seems a good idea */
     774         [ +  - ]:          4 :         if (inner_key.src.addr.ipv4_aligned != key->dst.addr.ipv4_aligned
     775         [ -  + ]:          4 :             || inner_key.dst.addr.ipv4_aligned != key->src.addr.ipv4_aligned) {
     776                 :          0 :             return false;
     777                 :            :         }
     778                 :            : 
     779                 :          4 :         key->src = inner_key.src;
     780                 :          4 :         key->dst = inner_key.dst;
     781                 :          4 :         key->nw_proto = inner_key.nw_proto;
     782                 :            : 
     783                 :          4 :         ok = extract_l4(key, l4, tail - l4, NULL, l3);
     784         [ +  - ]:          4 :         if (ok) {
     785                 :          4 :             conn_key_reverse(key);
     786                 :          4 :             *related = true;
     787                 :            :         }
     788                 :          4 :         return ok;
     789                 :            :     }
     790                 :            :     default:
     791                 :          0 :         return false;
     792                 :            :     }
     793                 :            : 
     794                 :         15 :     return true;
     795                 :            : }
     796                 :            : 
     797                 :            : static uint8_t
     798                 :         15 : reverse_icmp6_type(uint8_t type)
     799                 :            : {
     800      [ +  +  - ]:         15 :     switch (type) {
     801                 :            :     case ICMP6_ECHO_REQUEST:
     802                 :         11 :         return ICMP6_ECHO_REPLY;
     803                 :            :     case ICMP6_ECHO_REPLY:
     804                 :          4 :         return ICMP6_ECHO_REQUEST;
     805                 :            :     default:
     806                 :          0 :         OVS_NOT_REACHED();
     807                 :            :     }
     808                 :            : }
     809                 :            : 
     810                 :            : /* If 'related' is not NULL and the function is processing an ICMP
     811                 :            :  * error packet, extract the l3 and l4 fields from the nested header
     812                 :            :  * instead and set *related to true.  If 'related' is NULL we're
     813                 :            :  * already processing a nested header and no such recursion is
     814                 :            :  * possible */
     815                 :            : static inline bool
     816                 :         15 : extract_l4_icmp6(struct conn_key *key, const void *data, size_t size,
     817                 :            :                  bool *related)
     818                 :            : {
     819                 :         15 :     const struct icmp6_header *icmp6 = data;
     820                 :            : 
     821                 :            :     /* All the messages that we support need at least 4 bytes after
     822                 :            :      * the header */
     823         [ -  + ]:         15 :     if (size < sizeof *icmp6 + 4) {
     824                 :          0 :         return false;
     825                 :            :     }
     826                 :            : 
     827      [ +  -  - ]:         15 :     switch (icmp6->icmp6_type) {
     828                 :            :     case ICMP6_ECHO_REQUEST:
     829                 :            :     case ICMP6_ECHO_REPLY:
     830         [ -  + ]:         15 :         if (icmp6->icmp6_code != 0) {
     831                 :          0 :             return false;
     832                 :            :         }
     833                 :            :         /* Separate ICMP connection: identified using id */
     834                 :         15 :         key->src.icmp_id = key->dst.icmp_id = *(ovs_be16 *) (icmp6 + 1);
     835                 :         15 :         key->src.icmp_type = icmp6->icmp6_type;
     836                 :         15 :         key->dst.icmp_type = reverse_icmp6_type(icmp6->icmp6_type);
     837                 :         15 :         break;
     838                 :            :     case ICMP6_DST_UNREACH:
     839                 :            :     case ICMP6_PACKET_TOO_BIG:
     840                 :            :     case ICMP6_TIME_EXCEEDED:
     841                 :            :     case ICMP6_PARAM_PROB: {
     842                 :            :         /* ICMP packet part of another connection. We should
     843                 :            :          * extract the key from embedded packet header */
     844                 :            :         struct conn_key inner_key;
     845                 :          0 :         const char *l3 = (const char *) icmp6 + 8;
     846                 :          0 :         const char *tail = (const char *) data + size;
     847                 :          0 :         const char *l4 = NULL;
     848                 :            :         bool ok;
     849                 :            : 
     850         [ #  # ]:          0 :         if (!related) {
     851                 :          0 :             return false;
     852                 :            :         }
     853                 :            : 
     854                 :          0 :         memset(&inner_key, 0, sizeof inner_key);
     855                 :          0 :         inner_key.dl_type = htons(ETH_TYPE_IPV6);
     856                 :          0 :         ok = extract_l3_ipv6(&inner_key, l3, tail - l3, &l4);
     857         [ #  # ]:          0 :         if (!ok) {
     858                 :          0 :             return false;
     859                 :            :         }
     860                 :            : 
     861                 :            :         /* pf doesn't do this, but it seems a good idea */
     862         [ #  # ]:          0 :         if (!ipv6_addr_equals(&inner_key.src.addr.ipv6_aligned,
     863                 :          0 :                               &key->dst.addr.ipv6_aligned)
     864         [ #  # ]:          0 :             || !ipv6_addr_equals(&inner_key.dst.addr.ipv6_aligned,
     865                 :          0 :                                  &key->src.addr.ipv6_aligned)) {
     866                 :          0 :             return false;
     867                 :            :         }
     868                 :            : 
     869                 :          0 :         key->src = inner_key.src;
     870                 :          0 :         key->dst = inner_key.dst;
     871                 :          0 :         key->nw_proto = inner_key.nw_proto;
     872                 :            : 
     873                 :          0 :         ok = extract_l4(key, l4, tail - l4, NULL, l3);
     874         [ #  # ]:          0 :         if (ok) {
     875                 :          0 :             conn_key_reverse(key);
     876                 :          0 :             *related = true;
     877                 :            :         }
     878                 :          0 :         return ok;
     879                 :            :     }
     880                 :            :     default:
     881                 :          0 :         return false;
     882                 :            :     }
     883                 :            : 
     884                 :         15 :     return true;
     885                 :            : }
     886                 :            : 
     887                 :            : /* Extract l4 fields into 'key', which must already contain valid l3
     888                 :            :  * members.
     889                 :            :  *
     890                 :            :  * If 'related' is not NULL and an ICMP error packet is being
     891                 :            :  * processed, the function will extract the key from the packet nested
     892                 :            :  * in the ICMP paylod and set '*related' to true.
     893                 :            :  *
     894                 :            :  * If 'related' is NULL, it means that we're already parsing a header nested
     895                 :            :  * in an ICMP error.  In this case, we skip checksum and length validation. */
     896                 :            : static inline bool
     897                 :        626 : extract_l4(struct conn_key *key, const void *data, size_t size, bool *related,
     898                 :            :            const void *l3)
     899                 :            : {
     900         [ +  + ]:        626 :     if (key->nw_proto == IPPROTO_TCP) {
     901         [ +  - ]:       1086 :         return (!related || check_l4_tcp(key, data, size, l3))
     902 [ +  - ][ +  - ]:       1086 :                && extract_l4_tcp(key, data, size);
     903         [ +  + ]:         83 :     } else if (key->nw_proto == IPPROTO_UDP) {
     904         [ +  - ]:         94 :         return (!related || check_l4_udp(key, data, size, l3))
     905 [ +  + ][ +  - ]:         94 :                && extract_l4_udp(key, data, size);
     906         [ +  + ]:         34 :     } else if (key->dl_type == htons(ETH_TYPE_IP)
     907         [ +  - ]:         19 :                && key->nw_proto == IPPROTO_ICMP) {
     908         [ +  - ]:         38 :         return (!related || check_l4_icmp(data, size))
     909 [ +  - ][ +  - ]:         38 :                && extract_l4_icmp(key, data, size, related);
     910         [ +  - ]:         15 :     } else if (key->dl_type == htons(ETH_TYPE_IPV6)
     911         [ +  - ]:         15 :                && key->nw_proto == IPPROTO_ICMPV6) {
     912         [ +  - ]:         30 :         return (!related || check_l4_icmp6(key, data, size, l3))
     913 [ +  - ][ +  - ]:         30 :                && extract_l4_icmp6(key, data, size, related);
     914                 :            :     } else {
     915                 :          0 :         return false;
     916                 :            :     }
     917                 :            : }
     918                 :            : 
     919                 :            : static bool
     920                 :        624 : conn_key_extract(struct conntrack *ct, struct dp_packet *pkt, ovs_be16 dl_type,
     921                 :            :                  struct conn_lookup_ctx *ctx, uint16_t zone)
     922                 :            : {
     923                 :        624 :     const struct eth_header *l2 = dp_packet_l2(pkt);
     924                 :        624 :     const struct ip_header *l3 = dp_packet_l3(pkt);
     925                 :        624 :     const char *l4 = dp_packet_l4(pkt);
     926                 :        624 :     const char *tail = dp_packet_tail(pkt);
     927                 :            :     bool ok;
     928                 :            : 
     929                 :        624 :     memset(ctx, 0, sizeof *ctx);
     930                 :            : 
     931 [ +  - ][ +  - ]:        624 :     if (!l2 || !l3 || !l4) {
                 [ +  + ]
     932                 :          1 :         return false;
     933                 :            :     }
     934                 :            : 
     935                 :        623 :     ctx->key.zone = zone;
     936                 :            : 
     937                 :            :     /* XXX In this function we parse the packet (again, it has already
     938                 :            :      * gone through miniflow_extract()) for two reasons:
     939                 :            :      *
     940                 :            :      * 1) To extract the l3 addresses and l4 ports.
     941                 :            :      *    We already have the l3 and l4 headers' pointers.  Extracting
     942                 :            :      *    the l3 addresses and the l4 ports is really cheap, since they
     943                 :            :      *    can be found at fixed locations.
     944                 :            :      * 2) To extract the l4 type.
     945                 :            :      *    Extracting the l4 types, for IPv6 can be quite expensive, because
     946                 :            :      *    it's not at a fixed location.
     947                 :            :      *
     948                 :            :      * Here's a way to avoid (2) with the help of the datapath.
     949                 :            :      * The datapath doesn't keep the packet's extracted flow[1], so
     950                 :            :      * using that is not an option.  We could use the packet's matching
     951                 :            :      * megaflow, but we have to make sure that the l4 type (nw_proto)
     952                 :            :      * is unwildcarded.  This means either:
     953                 :            :      *
     954                 :            :      * a) dpif-netdev unwildcards the l4 type when a new flow is installed
     955                 :            :      *    if the actions contains ct().
     956                 :            :      *
     957                 :            :      * b) ofproto-dpif-xlate unwildcards the l4 type when translating a ct()
     958                 :            :      *    action.  This is already done in different actions, but it's
     959                 :            :      *    unnecessary for the kernel.
     960                 :            :      *
     961                 :            :      * ---
     962                 :            :      * [1] The reasons for this are that keeping the flow increases
     963                 :            :      *     (slightly) the cache footprint and increases computation
     964                 :            :      *     time as we move the packet around. Most importantly, the flow
     965                 :            :      *     should be updated by the actions and this can be slow, as
     966                 :            :      *     we use a sparse representation (miniflow).
     967                 :            :      *
     968                 :            :      */
     969                 :        623 :     ctx->key.dl_type = dl_type;
     970         [ +  + ]:        623 :     if (ctx->key.dl_type == htons(ETH_TYPE_IP)) {
     971                 :        578 :         ok = extract_l3_ipv4(&ctx->key, l3, tail - (char *) l3, NULL, true);
     972         [ +  - ]:         45 :     } else if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) {
     973                 :         45 :         ok = extract_l3_ipv6(&ctx->key, l3, tail - (char *) l3, NULL);
     974                 :            :     } else {
     975                 :          0 :         ok = false;
     976                 :            :     }
     977                 :            : 
     978         [ +  + ]:        623 :     if (ok) {
     979         [ +  - ]:        622 :         if (extract_l4(&ctx->key, l4, tail - l4, &ctx->related, l3)) {
     980                 :        622 :             ctx->hash = conn_key_hash(&ctx->key, ct->hash_basis);
     981                 :        622 :             return true;
     982                 :            :         }
     983                 :            :     }
     984                 :            : 
     985                 :          1 :     return false;
     986                 :            : }
     987                 :            : 
     988                 :            : /* Symmetric */
     989                 :            : static uint32_t
     990                 :        622 : conn_key_hash(const struct conn_key *key, uint32_t basis)
     991                 :            : {
     992                 :            :     uint32_t hsrc, hdst, hash;
     993                 :            :     int i;
     994                 :            : 
     995                 :        622 :     hsrc = hdst = basis;
     996                 :            : 
     997                 :            :     /* Hash the source and destination tuple */
     998         [ +  + ]:       3732 :     for (i = 0; i < sizeof(key->src) / sizeof(uint32_t); i++) {
     999                 :       3110 :         hsrc = hash_add(hsrc, ((uint32_t *) &key->src)[i]);
    1000                 :       3110 :         hdst = hash_add(hdst, ((uint32_t *) &key->dst)[i]);
    1001                 :            :     }
    1002                 :            : 
    1003                 :            :     /* Even if source and destination are swapped the hash will be the same. */
    1004                 :        622 :     hash = hsrc ^ hdst;
    1005                 :            : 
    1006                 :            :     /* Hash the rest of the key(L3 and L4 types and zone). */
    1007                 :        622 :     hash = hash_words((uint32_t *) &key->dst + 1,
    1008                 :            :                       (uint32_t *) (key + 1) - (uint32_t *) (&key->dst + 1),
    1009                 :            :                       hash);
    1010                 :            : 
    1011                 :        622 :     return hash;
    1012                 :            : }
    1013                 :            : 
    1014                 :            : static void
    1015                 :         84 : conn_key_reverse(struct conn_key *key)
    1016                 :            : {
    1017                 :            :     struct ct_endpoint tmp;
    1018                 :            : 
    1019                 :         84 :     tmp = key->src;
    1020                 :         84 :     key->src = key->dst;
    1021                 :         84 :     key->dst = tmp;
    1022                 :         84 : }
    1023                 :            : 
    1024                 :            : static void
    1025                 :        622 : conn_key_lookup(struct conntrack_bucket *ctb,
    1026                 :            :                 struct conn_lookup_ctx *ctx,
    1027                 :            :                 long long now)
    1028                 :            : {
    1029                 :        622 :     uint32_t hash = ctx->hash;
    1030                 :            :     struct conn *conn;
    1031                 :            : 
    1032                 :        622 :     ctx->conn = NULL;
    1033                 :            : 
    1034 [ +  + ][ -  + ]:        734 :     HMAP_FOR_EACH_WITH_HASH (conn, node, hash, &ctb->connections) {
    1035         [ +  + ]:        589 :         if (!memcmp(&conn->key, &ctx->key, sizeof(conn->key))
    1036         [ +  - ]:        210 :                 && !conn_expired(conn, now)) {
    1037                 :        210 :             ctx->conn = conn;
    1038                 :        210 :             ctx->reply = false;
    1039                 :        210 :             break;
    1040                 :            :         }
    1041         [ +  + ]:        379 :         if (!memcmp(&conn->rev_key, &ctx->key, sizeof(conn->rev_key))
    1042         [ +  - ]:        267 :                 && !conn_expired(conn, now)) {
    1043                 :        267 :             ctx->conn = conn;
    1044                 :        267 :             ctx->reply = true;
    1045                 :        267 :             break;
    1046                 :            :         }
    1047                 :            :     }
    1048                 :        622 : }
    1049                 :            : 
    1050                 :            : static enum ct_update_res
    1051                 :        474 : conn_update(struct conn *conn, struct conntrack_bucket *ctb,
    1052                 :            :             struct dp_packet *pkt, bool reply, long long now)
    1053                 :            : {
    1054                 :        474 :     return l4_protos[conn->key.nw_proto]->conn_update(conn, ctb, pkt,
    1055                 :            :                                                       reply, now);
    1056                 :            : }
    1057                 :            : 
    1058                 :            : static bool
    1059                 :        478 : conn_expired(struct conn *conn, long long now)
    1060                 :            : {
    1061                 :        478 :     return now >= conn->expiration;
    1062                 :            : }
    1063                 :            : 
    1064                 :            : static bool
    1065                 :        146 : valid_new(struct dp_packet *pkt, struct conn_key *key)
    1066                 :            : {
    1067                 :        146 :     return l4_protos[key->nw_proto]->valid_new(pkt);
    1068                 :            : }
    1069                 :            : 
    1070                 :            : static struct conn *
    1071                 :         80 : new_conn(struct conntrack_bucket *ctb, struct dp_packet *pkt,
    1072                 :            :          struct conn_key *key, long long now)
    1073                 :            : {
    1074                 :            :     struct conn *newconn;
    1075                 :            : 
    1076                 :         80 :     newconn = l4_protos[key->nw_proto]->new_conn(ctb, pkt, now);
    1077                 :            : 
    1078         [ +  - ]:         80 :     if (newconn) {
    1079                 :         80 :         newconn->key = *key;
    1080                 :            :     }
    1081                 :            : 
    1082                 :         80 :     return newconn;
    1083                 :            : }
    1084                 :            : 
    1085                 :            : static void
    1086                 :          4 : delete_conn(struct conn *conn)
    1087                 :            : {
    1088                 :          4 :     free(conn);
    1089                 :          4 : }
    1090                 :            : 
    1091                 :            : static void
    1092                 :        192 : ct_endpoint_to_ct_dpif_inet_addr(const struct ct_addr *a,
    1093                 :            :                                  union ct_dpif_inet_addr *b,
    1094                 :            :                                  ovs_be16 dl_type)
    1095                 :            : {
    1096         [ +  + ]:        192 :     if (dl_type == htons(ETH_TYPE_IP)) {
    1097                 :        180 :         b->ip = a->ipv4_aligned;
    1098         [ +  - ]:         12 :     } else if (dl_type == htons(ETH_TYPE_IPV6)){
    1099                 :         12 :         b->in6 = a->ipv6_aligned;
    1100                 :            :     }
    1101                 :        192 : }
    1102                 :            : 
    1103                 :            : static void
    1104                 :         96 : conn_key_to_tuple(const struct conn_key *key, struct ct_dpif_tuple *tuple)
    1105                 :            : {
    1106         [ +  + ]:         96 :     if (key->dl_type == htons(ETH_TYPE_IP)) {
    1107                 :         90 :         tuple->l3_type = AF_INET;
    1108         [ +  - ]:          6 :     } else if (key->dl_type == htons(ETH_TYPE_IPV6)) {
    1109                 :          6 :         tuple->l3_type = AF_INET6;
    1110                 :            :     }
    1111                 :         96 :     tuple->ip_proto = key->nw_proto;
    1112                 :         96 :     ct_endpoint_to_ct_dpif_inet_addr(&key->src.addr, &tuple->src,
    1113                 :         96 :                                      key->dl_type);
    1114                 :         96 :     ct_endpoint_to_ct_dpif_inet_addr(&key->dst.addr, &tuple->dst,
    1115                 :         96 :                                      key->dl_type);
    1116                 :            : 
    1117 [ +  + ][ +  + ]:         96 :     if (key->nw_proto == IPPROTO_ICMP || key->nw_proto == IPPROTO_ICMPV6) {
    1118                 :          4 :         tuple->icmp_id = key->src.icmp_id;
    1119                 :          4 :         tuple->icmp_type = key->src.icmp_type;
    1120                 :          4 :         tuple->icmp_code = key->src.icmp_code;
    1121                 :            :     } else {
    1122                 :         92 :         tuple->src_port = key->src.port;
    1123                 :         92 :         tuple->dst_port = key->dst.port;
    1124                 :            :     }
    1125                 :         96 : }
    1126                 :            : 
    1127                 :            : static void
    1128                 :         48 : conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry *entry,
    1129                 :            :                       long long now)
    1130                 :            : {
    1131                 :            :     struct ct_l4_proto *class;
    1132                 :            :     long long expiration;
    1133                 :         48 :     memset(entry, 0, sizeof *entry);
    1134                 :         48 :     conn_key_to_tuple(&conn->key, &entry->tuple_orig);
    1135                 :         48 :     conn_key_to_tuple(&conn->rev_key, &entry->tuple_reply);
    1136                 :            : 
    1137                 :         48 :     entry->zone = conn->key.zone;
    1138                 :         48 :     entry->mark = conn->mark;
    1139                 :            : 
    1140                 :         48 :     memcpy(&entry->labels, &conn->label, sizeof(entry->labels));
    1141                 :            :     /* Not implemented yet */
    1142                 :         48 :     entry->timestamp.start = 0;
    1143                 :         48 :     entry->timestamp.stop = 0;
    1144                 :            : 
    1145                 :         48 :     expiration = conn->expiration - now;
    1146         [ +  - ]:         48 :     entry->timeout = (expiration > 0) ? expiration / 1000 : 0;
    1147                 :            : 
    1148                 :         48 :     class = l4_protos[conn->key.nw_proto];
    1149         [ +  + ]:         48 :     if (class->conn_get_protoinfo) {
    1150                 :         46 :         class->conn_get_protoinfo(conn, &entry->protoinfo);
    1151                 :            :     }
    1152                 :         48 : }
    1153                 :            : 
    1154                 :            : int
    1155                 :         16 : conntrack_dump_start(struct conntrack *ct, struct conntrack_dump *dump,
    1156                 :            :                      const uint16_t *pzone)
    1157                 :            : {
    1158                 :         16 :     memset(dump, 0, sizeof(*dump));
    1159         [ -  + ]:         16 :     if (pzone) {
    1160                 :          0 :         dump->zone = *pzone;
    1161                 :          0 :         dump->filter_zone = true;
    1162                 :            :     }
    1163                 :         16 :     dump->ct = ct;
    1164                 :            : 
    1165                 :         16 :     return 0;
    1166                 :            : }
    1167                 :            : 
    1168                 :            : int
    1169                 :         64 : conntrack_dump_next(struct conntrack_dump *dump, struct ct_dpif_entry *entry)
    1170                 :            : {
    1171                 :         64 :     struct conntrack *ct = dump->ct;
    1172                 :         64 :     long long now = time_msec();
    1173                 :            : 
    1174         [ +  + ]:       4160 :     while (dump->bucket < CONNTRACK_BUCKETS) {
    1175                 :            :         struct hmap_node *node;
    1176                 :            : 
    1177                 :       4144 :         ct_lock_lock(&ct->buckets[dump->bucket].lock);
    1178                 :            :         for (;;) {
    1179                 :            :             struct conn *conn;
    1180                 :            : 
    1181                 :       4144 :             node = hmap_at_position(&ct->buckets[dump->bucket].connections,
    1182                 :            :                                     &dump->bucket_pos);
    1183         [ +  + ]:       4144 :             if (!node) {
    1184                 :       4096 :                 break;
    1185                 :            :             }
    1186                 :         48 :             INIT_CONTAINER(conn, node, node);
    1187 [ -  + ][ #  # ]:         48 :             if (!dump->filter_zone || conn->key.zone == dump->zone) {
    1188                 :         48 :                 conn_to_ct_dpif_entry(conn, entry, now);
    1189                 :         48 :                 break;
    1190                 :            :             }
    1191                 :            :             /* Else continue, until we find an entry in the appropriate zone
    1192                 :            :              * or the bucket has been scanned completely. */
    1193                 :          0 :         }
    1194                 :       4144 :         ct_lock_unlock(&ct->buckets[dump->bucket].lock);
    1195                 :            : 
    1196         [ +  + ]:       4144 :         if (!node) {
    1197                 :       4096 :             memset(&dump->bucket_pos, 0, sizeof dump->bucket_pos);
    1198                 :       4096 :             dump->bucket++;
    1199                 :            :         } else {
    1200                 :         48 :             return 0;
    1201                 :            :         }
    1202                 :            :     }
    1203                 :         16 :     return EOF;
    1204                 :            : }
    1205                 :            : 
    1206                 :            : int
    1207                 :         16 : conntrack_dump_done(struct conntrack_dump *dump OVS_UNUSED)
    1208                 :            : {
    1209                 :         16 :     return 0;
    1210                 :            : }
    1211                 :            : 
    1212                 :            : int
    1213                 :          2 : conntrack_flush(struct conntrack *ct, const uint16_t *zone)
    1214                 :            : {
    1215                 :            :     unsigned i;
    1216                 :            : 
    1217         [ +  + ]:        514 :     for (i = 0; i < CONNTRACK_BUCKETS; i++) {
    1218                 :            :         struct conn *conn, *next;
    1219                 :            : 
    1220                 :        512 :         ct_lock_lock(&ct->buckets[i].lock);
    1221 [ +  + ][ -  + ]:        514 :         HMAP_FOR_EACH_SAFE(conn, next, node, &ct->buckets[i].connections) {
                 [ +  + ]
    1222 [ -  + ][ #  # ]:          2 :             if (!zone || *zone == conn->key.zone) {
    1223                 :          2 :                 ovs_list_remove(&conn->exp_node);
    1224                 :          2 :                 hmap_remove(&ct->buckets[i].connections, &conn->node);
    1225                 :          2 :                 atomic_count_dec(&ct->n_conn);
    1226                 :          2 :                 delete_conn(conn);
    1227                 :            :             }
    1228                 :            :         }
    1229                 :        512 :         ct_lock_unlock(&ct->buckets[i].lock);
    1230                 :            :     }
    1231                 :            : 
    1232                 :          2 :     return 0;
    1233                 :            : }

Generated by: LCOV version 1.12