static struct subfacet *subfacet_create(struct facet *, enum odp_key_fitness,
const struct nlattr *key,
- size_t key_len, ovs_be16 initial_tci);
+ size_t key_len, ovs_be16 initial_tci,
+ long long int now);
static struct subfacet *subfacet_find(struct ofproto_dpif *,
const struct nlattr *key, size_t key_len);
static void subfacet_destroy(struct subfacet *);
}
/* Handles 'miss', which matches 'facet'. May add any required datapath
- * operations to 'ops', incrementing '*n_ops' for each new op. */
+ * operations to 'ops', incrementing '*n_ops' for each new op.
+ *
+ * All of the packets in 'miss' are considered to have arrived at time 'now'.
+ * This is really important only for new facets: if we just called time_msec()
+ * here, then the new subfacet or its packets could look (occasionally) as
+ * though it was used some time after the facet was used. That can make a
+ * one-packet flow look like it has a nonzero duration, which looks odd in
+ * e.g. NetFlow statistics. */
static void
handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet,
+ long long int now,
struct flow_miss_op *ops, size_t *n_ops)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
subfacet = subfacet_create(facet,
miss->key_fitness, miss->key, miss->key_len,
- miss->initial_tci);
+ miss->initial_tci, now);
LIST_FOR_EACH (packet, list_node, &miss->packets) {
struct flow_miss_op *op = &ops[*n_ops];
subfacet_make_actions(subfacet, packet, &odp_actions);
}
- dpif_flow_stats_extract(&facet->flow, packet, time_msec(), &stats);
+ dpif_flow_stats_extract(&facet->flow, packet, now, &stats);
subfacet_update_stats(subfacet, &stats);
if (subfacet->actions_len) {
struct flow_miss_op *ops, size_t *n_ops)
{
struct facet *facet;
+ long long int now;
uint32_t hash;
/* The caller must ensure that miss->hmap_node.hash contains
}
facet = facet_create(rule, &miss->flow, hash);
+ now = facet->used;
+ } else {
+ now = time_msec();
}
- handle_flow_miss_with_facet(miss, facet, ops, n_ops);
+ handle_flow_miss_with_facet(miss, facet, now, ops, n_ops);
}
/* Like odp_flow_key_to_flow(), this function converts the 'key_len' bytes of
* subfacet_make_actions(). */
static struct subfacet *
subfacet_create(struct facet *facet, enum odp_key_fitness key_fitness,
- const struct nlattr *key, size_t key_len, ovs_be16 initial_tci)
+ const struct nlattr *key, size_t key_len,
+ ovs_be16 initial_tci, long long int now)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
uint32_t key_hash = odp_flow_key_hash(key, key_len);
if (list_is_empty(&facet->subfacets)) {
subfacet = &facet->one_subfacet;
-
- /* This subfacet should conceptually be created, and have its first
- * packet pass through, at the same time that its facet was created.
- * If we called time_msec() here, then the subfacet could look
- * (occasionally) as though it was used some time after the facet was
- * used. That can make a one-packet flow look like it has a nonzero
- * duration, which looks odd in e.g. NetFlow statistics. */
- subfacet->used = facet->used;
} else {
subfacet = subfacet_find__(ofproto, key, key_len, key_hash,
&facet->flow);
}
subfacet = xmalloc(sizeof *subfacet);
- subfacet->used = time_msec();
}
hmap_insert(&ofproto->subfacets, &subfacet->hmap_node, key_hash);
subfacet->key = NULL;
subfacet->key_len = 0;
}
+ subfacet->used = now;
subfacet->dp_packet_count = 0;
subfacet->dp_byte_count = 0;
subfacet->actions_len = 0;