LCOV - code coverage report
Current view: top level - ofproto - netflow.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 190 205 92.7 %
Date: 2016-09-14 01:02:56 Functions: 16 16 100.0 %
Branches: 55 82 67.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2008, 2009, 2010, 2011, 2013, 2014, 2015 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <config.h>
      18                 :            : #include "netflow.h"
      19                 :            : #include <arpa/inet.h>
      20                 :            : #include <errno.h>
      21                 :            : #include <stdlib.h>
      22                 :            : #include <unistd.h>
      23                 :            : #include "byte-order.h"
      24                 :            : #include "collectors.h"
      25                 :            : #include "dpif.h"
      26                 :            : #include "flow.h"
      27                 :            : #include "lib/netflow.h"
      28                 :            : #include "openvswitch/ofpbuf.h"
      29                 :            : #include "ofproto.h"
      30                 :            : #include "ofproto/netflow.h"
      31                 :            : #include "packets.h"
      32                 :            : #include "poll-loop.h"
      33                 :            : #include "socket-util.h"
      34                 :            : #include "timeval.h"
      35                 :            : #include "util.h"
      36                 :            : #include "openvswitch/vlog.h"
      37                 :            : 
      38                 :       1288 : VLOG_DEFINE_THIS_MODULE(netflow);
      39                 :            : 
      40                 :            : struct netflow {
      41                 :            :     uint8_t engine_type;          /* Value of engine_type to use. */
      42                 :            :     uint8_t engine_id;            /* Value of engine_id to use. */
      43                 :            :     long long int boot_time;      /* Time when netflow_create() was called. */
      44                 :            :     struct collectors *collectors; /* NetFlow collectors. */
      45                 :            :     bool add_id_to_iface;         /* Put the 7 least significiant bits of
      46                 :            :                                    * 'engine_id' into the most significant
      47                 :            :                                    * bits of the interface fields. */
      48                 :            :     uint32_t netflow_cnt;         /* Flow sequence number for NetFlow. */
      49                 :            :     struct ofpbuf packet;         /* NetFlow packet being accumulated. */
      50                 :            :     long long int active_timeout; /* Timeout for flows that are still active. */
      51                 :            :     long long int next_timeout;   /* Next scheduled active timeout. */
      52                 :            :     long long int reconfig_time;  /* When we reconfigured the timeouts. */
      53                 :            : 
      54                 :            :     struct hmap flows;            /* Contains 'netflow_flows'. */
      55                 :            : 
      56                 :            :     struct ovs_refcount ref_cnt;
      57                 :            : };
      58                 :            : 
      59                 :            : struct netflow_flow {
      60                 :            :     struct hmap_node hmap_node;
      61                 :            : 
      62                 :            :     long long int last_expired;   /* Time this flow last timed out. */
      63                 :            :     long long int created;        /* Time flow was created since time out. */
      64                 :            : 
      65                 :            :     ofp_port_t output_iface;      /* Output interface index. */
      66                 :            :     uint16_t tcp_flags;           /* Bitwise-OR of all TCP flags seen. */
      67                 :            : 
      68                 :            :     ofp_port_t in_port;           /* Input port. */
      69                 :            :     ovs_be32 nw_src;              /* IPv4 source address. */
      70                 :            :     ovs_be32 nw_dst;              /* IPv4 destination address. */
      71                 :            :     uint8_t nw_tos;               /* IP ToS (including DSCP and ECN). */
      72                 :            :     uint8_t nw_proto;             /* IP protocol. */
      73                 :            :     ovs_be16 tp_src;              /* TCP/UDP/SCTP source port. */
      74                 :            :     ovs_be16 tp_dst;              /* TCP/UDP/SCTP destination port. */
      75                 :            : 
      76                 :            :     uint64_t packet_count;        /* Packets from subrules. */
      77                 :            :     uint64_t byte_count;          /* Bytes from subrules. */
      78                 :            :     long long int used;           /* Last-used time (0 if never used). */
      79                 :            : };
      80                 :            : 
      81                 :            : static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
      82                 :            : static atomic_count netflow_count = ATOMIC_COUNT_INIT(0);
      83                 :            : 
      84                 :            : static struct netflow_flow *netflow_flow_lookup(const struct netflow *,
      85                 :            :                                                 const struct flow *)
      86                 :            :     OVS_REQUIRES(mutex);
      87                 :            : static uint32_t netflow_flow_hash(const struct flow *);
      88                 :            : static void netflow_expire__(struct netflow *, struct netflow_flow *)
      89                 :            :     OVS_REQUIRES(mutex);
      90                 :            : static void netflow_run__(struct netflow *) OVS_REQUIRES(mutex);
      91                 :            : 
      92                 :            : void
      93                 :         26 : netflow_mask_wc(const struct flow *flow, struct flow_wildcards *wc)
      94                 :            : {
      95         [ -  + ]:         26 :     if (flow->dl_type != htons(ETH_TYPE_IP)) {
      96                 :          0 :         return;
      97                 :            :     }
      98                 :         26 :     memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
      99                 :         26 :     memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
     100                 :         26 :     memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
     101                 :         26 :     flow_unwildcard_tp_ports(flow, wc);
     102                 :         26 :     wc->masks.nw_tos |= IP_DSCP_MASK;
     103                 :            : }
     104                 :            : 
     105                 :            : static void
     106                 :         32 : gen_netflow_rec(struct netflow *nf, struct netflow_flow *nf_flow,
     107                 :            :                 uint32_t packet_count, uint32_t byte_count)
     108                 :            :     OVS_REQUIRES(mutex)
     109                 :            : {
     110                 :            :     struct netflow_v5_header *nf_hdr;
     111                 :            :     struct netflow_v5_record *nf_rec;
     112                 :            : 
     113         [ +  + ]:         32 :     if (!nf->packet.size) {
     114                 :            :         struct timespec now;
     115                 :            : 
     116                 :         19 :         time_wall_timespec(&now);
     117                 :            : 
     118                 :         19 :         nf_hdr = ofpbuf_put_zeros(&nf->packet, sizeof *nf_hdr);
     119                 :         19 :         nf_hdr->version = htons(NETFLOW_V5_VERSION);
     120                 :         19 :         nf_hdr->count = htons(0);
     121                 :         19 :         nf_hdr->sysuptime = htonl(time_msec() - nf->boot_time);
     122                 :         19 :         nf_hdr->unix_secs = htonl(now.tv_sec);
     123                 :         19 :         nf_hdr->unix_nsecs = htonl(now.tv_nsec);
     124                 :         19 :         nf_hdr->engine_type = nf->engine_type;
     125                 :         19 :         nf_hdr->engine_id = nf->engine_id;
     126                 :         19 :         nf_hdr->sampling_interval = htons(0);
     127                 :            :     }
     128                 :            : 
     129                 :         32 :     nf_hdr = nf->packet.data;
     130                 :         32 :     nf_hdr->count = htons(ntohs(nf_hdr->count) + 1);
     131                 :         32 :     nf_hdr->flow_seq = htonl(nf->netflow_cnt++);
     132                 :            : 
     133                 :         32 :     nf_rec = ofpbuf_put_zeros(&nf->packet, sizeof *nf_rec);
     134                 :         32 :     nf_rec->src_addr = nf_flow->nw_src;
     135                 :         32 :     nf_rec->dst_addr = nf_flow->nw_dst;
     136                 :         32 :     nf_rec->nexthop = htonl(0);
     137         [ -  + ]:         32 :     if (nf->add_id_to_iface) {
     138                 :          0 :         uint16_t iface = (nf->engine_id & 0x7f) << 9;
     139                 :          0 :         nf_rec->input = htons(iface | (ofp_to_u16(nf_flow->in_port) & 0x1ff));
     140                 :          0 :         nf_rec->output = htons(iface
     141                 :          0 :             | (ofp_to_u16(nf_flow->output_iface) & 0x1ff));
     142                 :            :     } else {
     143                 :         32 :         nf_rec->input = htons(ofp_to_u16(nf_flow->in_port));
     144                 :         32 :         nf_rec->output = htons(ofp_to_u16(nf_flow->output_iface));
     145                 :            :     }
     146                 :         32 :     nf_rec->packet_count = htonl(packet_count);
     147                 :         32 :     nf_rec->byte_count = htonl(byte_count);
     148                 :         32 :     nf_rec->init_time = htonl(nf_flow->created - nf->boot_time);
     149                 :         32 :     nf_rec->used_time = htonl(MAX(nf_flow->created, nf_flow->used)
     150                 :         32 :                              - nf->boot_time);
     151         [ +  + ]:         32 :     if (nf_flow->nw_proto == IPPROTO_ICMP) {
     152                 :            :         /* In NetFlow, the ICMP type and code are concatenated and
     153                 :            :          * placed in the 'dst_port' field. */
     154                 :          8 :         uint8_t type = ntohs(nf_flow->tp_src);
     155                 :          8 :         uint8_t code = ntohs(nf_flow->tp_dst);
     156                 :          8 :         nf_rec->src_port = htons(0);
     157                 :          8 :         nf_rec->dst_port = htons((type << 8) | code);
     158                 :            :     } else {
     159                 :         24 :         nf_rec->src_port = nf_flow->tp_src;
     160                 :         24 :         nf_rec->dst_port = nf_flow->tp_dst;
     161                 :            :     }
     162                 :         32 :     nf_rec->tcp_flags = (uint8_t) nf_flow->tcp_flags;
     163                 :         32 :     nf_rec->ip_proto = nf_flow->nw_proto;
     164                 :         32 :     nf_rec->ip_tos = nf_flow->nw_tos & IP_DSCP_MASK;
     165                 :            : 
     166                 :            :     /* NetFlow messages are limited to 30 records. */
     167         [ -  + ]:         32 :     if (ntohs(nf_hdr->count) >= 30) {
     168                 :          0 :         netflow_run__(nf);
     169                 :            :     }
     170                 :         32 : }
     171                 :            : 
     172                 :            : void
     173                 :        252 : netflow_flow_update(struct netflow *nf, const struct flow *flow,
     174                 :            :                     ofp_port_t output_iface,
     175                 :            :                     const struct dpif_flow_stats *stats)
     176                 :            :     OVS_EXCLUDED(mutex)
     177                 :            : {
     178                 :            :     struct netflow_flow *nf_flow;
     179                 :            :     long long int used;
     180                 :            : 
     181                 :            :     /* NetFlow only reports on IP packets. */
     182         [ -  + ]:        252 :     if (flow->dl_type != htons(ETH_TYPE_IP)) {
     183                 :          0 :         return;
     184                 :            :     }
     185                 :            : 
     186                 :        252 :     ovs_mutex_lock(&mutex);
     187                 :        252 :     nf_flow = netflow_flow_lookup(nf, flow);
     188         [ +  + ]:        252 :     if (!nf_flow) {
     189                 :         14 :         nf_flow = xzalloc(sizeof *nf_flow);
     190                 :         14 :         nf_flow->in_port = flow->in_port.ofp_port;
     191                 :         14 :         nf_flow->nw_src = flow->nw_src;
     192                 :         14 :         nf_flow->nw_dst = flow->nw_dst;
     193                 :         14 :         nf_flow->nw_tos = flow->nw_tos;
     194                 :         14 :         nf_flow->nw_proto = flow->nw_proto;
     195                 :         14 :         nf_flow->tp_src = flow->tp_src;
     196                 :         14 :         nf_flow->tp_dst = flow->tp_dst;
     197                 :         14 :         nf_flow->created = stats->used;
     198                 :         14 :         nf_flow->output_iface = output_iface;
     199                 :         14 :         hmap_insert(&nf->flows, &nf_flow->hmap_node, netflow_flow_hash(flow));
     200                 :            :     }
     201                 :            : 
     202         [ +  + ]:        252 :     if (nf_flow->output_iface != output_iface) {
     203                 :          2 :         netflow_expire__(nf, nf_flow);
     204                 :          2 :         nf_flow->created = stats->used;
     205                 :          2 :         nf_flow->output_iface = output_iface;
     206                 :            :     }
     207                 :            : 
     208                 :        252 :     nf_flow->packet_count += stats->n_packets;
     209                 :        252 :     nf_flow->byte_count += stats->n_bytes;
     210                 :        252 :     nf_flow->tcp_flags |= stats->tcp_flags;
     211                 :            : 
     212                 :        252 :     used = MAX(nf_flow->used, stats->used);
     213         [ +  - ]:        252 :     if (nf_flow->used != used) {
     214                 :        252 :         nf_flow->used = used;
     215 [ +  - ][ +  + ]:        252 :         if (!nf->active_timeout || !nf_flow->last_expired
     216         [ -  + ]:        238 :             || nf->reconfig_time > nf_flow->last_expired) {
     217                 :            :             /* Keep the time updated to prevent a flood of expiration in
     218                 :            :              * the future. */
     219                 :         14 :             nf_flow->last_expired = time_msec();
     220                 :            :         }
     221                 :            :     }
     222                 :            : 
     223                 :        252 :     ovs_mutex_unlock(&mutex);
     224                 :            : }
     225                 :            : 
     226                 :            : static void
     227                 :         35 : netflow_expire__(struct netflow *nf, struct netflow_flow *nf_flow)
     228                 :            :     OVS_REQUIRES(mutex)
     229                 :            : {
     230                 :            :     uint64_t pkts, bytes;
     231                 :            : 
     232                 :         35 :     pkts = nf_flow->packet_count;
     233                 :         35 :     bytes = nf_flow->byte_count;
     234                 :            : 
     235                 :         35 :     nf_flow->last_expired += nf->active_timeout;
     236                 :            : 
     237         [ +  + ]:         35 :     if (pkts == 0) {
     238                 :          3 :         return;
     239                 :            :     }
     240                 :            : 
     241         [ +  - ]:         32 :     if ((bytes >> 32) <= 175) {
     242                 :            :         /* NetFlow v5 records are limited to 32-bit counters.  If we've wrapped
     243                 :            :          * a counter, send as multiple records so we don't lose track of any
     244                 :            :          * traffic.  We try to evenly distribute the packet and byte counters,
     245                 :            :          * so that the bytes-per-packet lengths don't look wonky across the
     246                 :            :          * records. */
     247         [ +  + ]:         64 :         while (bytes) {
     248                 :         32 :             int n_recs = (bytes + UINT32_MAX - 1) / UINT32_MAX;
     249                 :         32 :             uint32_t pkt_count = pkts / n_recs;
     250                 :         32 :             uint32_t byte_count = bytes / n_recs;
     251                 :            : 
     252                 :         32 :             gen_netflow_rec(nf, nf_flow, pkt_count, byte_count);
     253                 :            : 
     254                 :         32 :             pkts -= pkt_count;
     255                 :         32 :             bytes -= byte_count;
     256                 :            :         }
     257                 :            :     } else {
     258                 :            :         /* In 600 seconds, a 10GbE link can theoretically transmit 75 * 10**10
     259                 :            :          * == 175 * 2**32 bytes.  The byte counter is bigger than that, so it's
     260                 :            :          * probably a bug--for example, the netdev code uses UINT64_MAX to
     261                 :            :          * report "unknown value", and perhaps that has leaked through to here.
     262                 :            :          *
     263                 :            :          * We wouldn't want to hit the loop above in this case, because it
     264                 :            :          * would try to send up to UINT32_MAX netflow records, which would take
     265                 :            :          * a long time.
     266                 :            :          */
     267                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
     268                 :            : 
     269         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "impossible byte counter %"PRIu64, bytes);
     270                 :            :     }
     271                 :            : 
     272                 :            :     /* Update flow tracking data. */
     273                 :         32 :     nf_flow->packet_count = 0;
     274                 :         32 :     nf_flow->byte_count = 0;
     275                 :         32 :     nf_flow->tcp_flags = 0;
     276                 :            : }
     277                 :            : 
     278                 :            : void
     279                 :         12 : netflow_flow_clear(struct netflow *nf, const struct flow *flow)
     280                 :            :     OVS_EXCLUDED(mutex)
     281                 :            : {
     282                 :            :     struct netflow_flow *nf_flow;
     283                 :            : 
     284                 :         12 :     ovs_mutex_lock(&mutex);
     285                 :         12 :     nf_flow = netflow_flow_lookup(nf, flow);
     286         [ +  - ]:         12 :     if (nf_flow) {
     287                 :         12 :         netflow_expire__(nf, nf_flow);
     288                 :         12 :         hmap_remove(&nf->flows, &nf_flow->hmap_node);
     289                 :         12 :         free(nf_flow);
     290                 :            :     }
     291                 :         12 :     ovs_mutex_unlock(&mutex);
     292                 :         12 : }
     293                 :            : 
     294                 :            : /* Returns true if it's time to send out a round of NetFlow active timeouts,
     295                 :            :  * false otherwise. */
     296                 :            : static void
     297                 :       1336 : netflow_run__(struct netflow *nf) OVS_REQUIRES(mutex)
     298                 :            : {
     299                 :       1336 :     long long int now = time_msec();
     300                 :            :     struct netflow_flow *nf_flow, *next;
     301                 :            : 
     302         [ +  + ]:       1336 :     if (nf->packet.size) {
     303                 :         18 :         collectors_send(nf->collectors, nf->packet.data, nf->packet.size);
     304                 :         18 :         nf->packet.size = 0;
     305                 :            :     }
     306                 :            : 
     307 [ +  - ][ +  + ]:       1336 :     if (!nf->active_timeout || now < nf->next_timeout) {
     308                 :       1199 :         return;
     309                 :            :     }
     310                 :            : 
     311                 :        137 :     nf->next_timeout = now + 1000;
     312                 :            : 
     313 [ +  + ][ -  + ]:        389 :     HMAP_FOR_EACH_SAFE (nf_flow, next, hmap_node, &nf->flows) {
                 [ +  + ]
     314         [ +  + ]:        252 :         if (now > nf_flow->last_expired + nf->active_timeout) {
     315                 :         21 :             bool idle = nf_flow->used < nf_flow->last_expired;
     316                 :         21 :             netflow_expire__(nf, nf_flow);
     317                 :            : 
     318         [ -  + ]:         21 :             if (idle) {
     319                 :            :                 /* If the netflow_flow hasn't been used in a while, it's
     320                 :            :                  * possible the upper layer lost track of it. */
     321                 :          0 :                 hmap_remove(&nf->flows, &nf_flow->hmap_node);
     322                 :          0 :                 free(nf_flow);
     323                 :            :             }
     324                 :            :         }
     325                 :            :     }
     326                 :            : }
     327                 :            : 
     328                 :            : void
     329                 :       1336 : netflow_run(struct netflow *nf)
     330                 :            : {
     331                 :       1336 :     ovs_mutex_lock(&mutex);
     332                 :       1336 :     netflow_run__(nf);
     333                 :       1336 :     ovs_mutex_unlock(&mutex);
     334                 :       1336 : }
     335                 :            : 
     336                 :            : void
     337                 :       1336 : netflow_wait(struct netflow *nf) OVS_EXCLUDED(mutex)
     338                 :            : {
     339                 :       1336 :     ovs_mutex_lock(&mutex);
     340         [ +  - ]:       1336 :     if (nf->active_timeout) {
     341                 :       1336 :         poll_timer_wait_until(nf->next_timeout);
     342                 :            :     }
     343         [ +  + ]:       1336 :     if (nf->packet.size) {
     344                 :         14 :         poll_immediate_wake();
     345                 :            :     }
     346                 :       1336 :     ovs_mutex_unlock(&mutex);
     347                 :       1336 : }
     348                 :            : 
     349                 :            : int
     350                 :          6 : netflow_set_options(struct netflow *nf,
     351                 :            :                     const struct netflow_options *nf_options)
     352                 :            :     OVS_EXCLUDED(mutex)
     353                 :            : {
     354                 :          6 :     int error = 0;
     355                 :            :     long long int old_timeout;
     356                 :            : 
     357                 :          6 :     ovs_mutex_lock(&mutex);
     358                 :          6 :     nf->engine_type = nf_options->engine_type;
     359                 :          6 :     nf->engine_id = nf_options->engine_id;
     360                 :          6 :     nf->add_id_to_iface = nf_options->add_id_to_iface;
     361                 :            : 
     362                 :          6 :     collectors_destroy(nf->collectors);
     363                 :          6 :     collectors_create(&nf_options->collectors, 0, &nf->collectors);
     364                 :            : 
     365                 :          6 :     old_timeout = nf->active_timeout;
     366         [ +  - ]:          6 :     if (nf_options->active_timeout >= 0) {
     367                 :          6 :         nf->active_timeout = nf_options->active_timeout;
     368                 :            :     } else {
     369                 :          0 :         nf->active_timeout = NF_ACTIVE_TIMEOUT_DEFAULT;
     370                 :            :     }
     371                 :          6 :     nf->active_timeout *= 1000;
     372         [ +  - ]:          6 :     if (old_timeout != nf->active_timeout) {
     373                 :          6 :         nf->reconfig_time = time_msec();
     374                 :          6 :         nf->next_timeout = time_msec();
     375                 :            :     }
     376                 :          6 :     ovs_mutex_unlock(&mutex);
     377                 :            : 
     378                 :          6 :     return error;
     379                 :            : }
     380                 :            : 
     381                 :            : struct netflow *
     382                 :          6 : netflow_create(void)
     383                 :            : {
     384                 :          6 :     struct netflow *nf = xzalloc(sizeof *nf);
     385                 :            : 
     386                 :          6 :     nf->engine_type = 0;
     387                 :          6 :     nf->engine_id = 0;
     388                 :          6 :     nf->boot_time = time_msec();
     389                 :          6 :     nf->collectors = NULL;
     390                 :          6 :     nf->add_id_to_iface = false;
     391                 :          6 :     nf->netflow_cnt = 0;
     392                 :          6 :     hmap_init(&nf->flows);
     393                 :          6 :     ovs_refcount_init(&nf->ref_cnt);
     394                 :          6 :     ofpbuf_init(&nf->packet, 1500);
     395                 :          6 :     atomic_count_inc(&netflow_count);
     396                 :          6 :     return nf;
     397                 :            : }
     398                 :            : 
     399                 :            : struct netflow *
     400                 :         76 : netflow_ref(const struct netflow *nf_)
     401                 :            : {
     402                 :         76 :     struct netflow *nf = CONST_CAST(struct netflow *, nf_);
     403         [ +  - ]:         76 :     if (nf) {
     404                 :         76 :         ovs_refcount_ref(&nf->ref_cnt);
     405                 :            :     }
     406                 :         76 :     return nf;
     407                 :            : }
     408                 :            : 
     409                 :            : void
     410                 :        823 : netflow_unref(struct netflow *nf)
     411                 :            : {
     412 [ +  + ][ -  + ]:        823 :     if (nf && ovs_refcount_unref_relaxed(&nf->ref_cnt) == 1) {
     413                 :          0 :         atomic_count_dec(&netflow_count);
     414                 :          0 :         collectors_destroy(nf->collectors);
     415                 :          0 :         ofpbuf_uninit(&nf->packet);
     416                 :          0 :         free(nf);
     417                 :            :     }
     418                 :        823 : }
     419                 :            : 
     420                 :            : /* Returns true if there exist any netflow objects, false otherwise.
     421                 :            :  * Callers must cope with transient false positives, i.e., there is no tight
     422                 :            :  * synchronization with the count and the actual existence of netflow objects.
     423                 :            :  */
     424                 :            : bool
     425                 :       6236 : netflow_exists(void)
     426                 :            : {
     427                 :       6236 :     return atomic_count_get(&netflow_count) > 0;
     428                 :            : }
     429                 :            : 
     430                 :            : /* Helpers. */
     431                 :            : 
     432                 :            : static struct netflow_flow *
     433                 :        264 : netflow_flow_lookup(const struct netflow *nf, const struct flow *flow)
     434                 :            :     OVS_REQUIRES(mutex)
     435                 :            : {
     436                 :            :     struct netflow_flow *nf_flow;
     437                 :            : 
     438 [ +  + ][ -  + ]:        264 :     HMAP_FOR_EACH_WITH_HASH (nf_flow, hmap_node, netflow_flow_hash(flow),
     439                 :            :                              &nf->flows) {
     440         [ +  - ]:        250 :         if (flow->in_port.ofp_port == nf_flow->in_port
     441         [ +  - ]:        250 :             && flow->nw_src == nf_flow->nw_src
     442         [ +  - ]:        250 :             && flow->nw_dst == nf_flow->nw_dst
     443         [ +  - ]:        250 :             && flow->nw_tos == nf_flow->nw_tos
     444         [ +  - ]:        250 :             && flow->nw_proto == nf_flow->nw_proto
     445         [ +  - ]:        250 :             && flow->tp_src == nf_flow->tp_src
     446         [ +  - ]:        250 :             && flow->tp_dst == nf_flow->tp_dst) {
     447                 :        250 :             return nf_flow;
     448                 :            :         }
     449                 :            :     }
     450                 :            : 
     451                 :         14 :     return NULL;
     452                 :            : }
     453                 :            : 
     454                 :            : static uint32_t
     455                 :        278 : netflow_flow_hash(const struct flow *flow)
     456                 :            : {
     457                 :        278 :     uint32_t hash = 0;
     458                 :            : 
     459                 :        278 :     hash = hash_add(hash, (OVS_FORCE uint32_t) flow->in_port.ofp_port);
     460                 :        278 :     hash = hash_add(hash, ntohl(flow->nw_src));
     461                 :        278 :     hash = hash_add(hash, ntohl(flow->nw_dst));
     462                 :        278 :     hash = hash_add(hash, flow->nw_tos);
     463                 :        278 :     hash = hash_add(hash, flow->nw_proto);
     464                 :        278 :     hash = hash_add(hash, ntohs(flow->tp_src));
     465                 :        278 :     hash = hash_add(hash, ntohs(flow->tp_dst));
     466                 :            : 
     467                 :        278 :     return hash_finish(hash, 28);
     468                 :            : }

Generated by: LCOV version 1.12