- /* NetFlow v5 records are limited to 32-bit counters. If we've wrapped
- * a counter, send as multiple records so we don't lose track of any
- * traffic. We try to evenly distribute the packet and byte counters,
- * so that the bytes-per-packet lengths don't look wonky across the
- * records. */
- while (byte_delta > UINT32_MAX) {
- uint32_t n_recs = byte_delta >> 32;
- uint32_t pkt_count = pkt_delta / n_recs;
- uint32_t byte_count = byte_delta / n_recs;
+ ovs_mutex_lock(&mutex);
+ nf_flow = netflow_flow_lookup(nf, flow);
+ if (!nf_flow) {
+ nf_flow = xzalloc(sizeof *nf_flow);
+ nf_flow->in_port = flow->in_port.ofp_port;
+ nf_flow->nw_src = flow->nw_src;
+ nf_flow->nw_dst = flow->nw_dst;
+ nf_flow->nw_tos = flow->nw_tos;
+ nf_flow->nw_proto = flow->nw_proto;
+ nf_flow->tp_src = flow->tp_src;
+ nf_flow->tp_dst = flow->tp_dst;
+ nf_flow->created = stats->used;
+ nf_flow->output_iface = output_iface;
+ hmap_insert(&nf->flows, &nf_flow->hmap_node, netflow_flow_hash(flow));
+ }
+
+ if (nf_flow->output_iface != output_iface) {
+ netflow_expire__(nf, nf_flow);
+ nf_flow->created = stats->used;
+ nf_flow->output_iface = output_iface;
+ }
+
+ nf_flow->packet_count += stats->n_packets;
+ nf_flow->byte_count += stats->n_bytes;
+ nf_flow->tcp_flags |= stats->tcp_flags;
+
+ used = MAX(nf_flow->used, stats->used);
+ if (nf_flow->used != used) {
+ nf_flow->used = used;
+ if (!nf->active_timeout || !nf_flow->last_expired
+ || nf->reconfig_time > nf_flow->last_expired) {
+ /* Keep the time updated to prevent a flood of expiration in
+ * the future. */
+ nf_flow->last_expired = time_msec();
+ }
+ }
+
+ ovs_mutex_unlock(&mutex);
+}
+
+static void
+netflow_expire__(struct netflow *nf, struct netflow_flow *nf_flow)
+ OVS_REQUIRES(mutex)
+{
+ uint64_t pkts, bytes;
+
+ pkts = nf_flow->packet_count;
+ bytes = nf_flow->byte_count;