+ facet->prev_used = facet->used;
+ }
+
+ return true;
+}
+
+/* Updates 'facet''s used time. Caller is responsible for calling
+ * facet_push_stats() to update the flows which 'facet' resubmits into. */
+static void
+facet_update_time(struct facet *facet, long long int used)
+{
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
+ if (used > facet->used) {
+ facet->used = used;
+ if (used > facet->rule->used) {
+ facet->rule->used = used;
+ }
+ netflow_flow_update_time(ofproto->netflow, &facet->nf_flow, used);
+ }
+}
+
+static void
+facet_reset_counters(struct facet *facet)
+{
+ facet->packet_count = 0;
+ facet->byte_count = 0;
+ facet->prev_packet_count = 0;
+ facet->prev_byte_count = 0;
+ facet->accounted_bytes = 0;
+}
+
+static void
+facet_push_stats(struct facet *facet)
+{
+ uint64_t new_packets, new_bytes;
+
+ assert(facet->packet_count >= facet->prev_packet_count);
+ assert(facet->byte_count >= facet->prev_byte_count);
+ assert(facet->used >= facet->prev_used);
+
+ new_packets = facet->packet_count - facet->prev_packet_count;
+ new_bytes = facet->byte_count - facet->prev_byte_count;
+
+ if (new_packets || new_bytes || facet->used > facet->prev_used) {
+ facet->prev_packet_count = facet->packet_count;
+ facet->prev_byte_count = facet->byte_count;
+ facet->prev_used = facet->used;
+
+ flow_push_stats(facet->rule, &facet->flow,
+ new_packets, new_bytes, facet->used);
+
+ update_mirror_stats(ofproto_dpif_cast(facet->rule->up.ofproto),
+ facet->mirrors, new_packets, new_bytes);
+ }
+}
+
+struct ofproto_push {
+ struct action_xlate_ctx ctx;
+ uint64_t packets;
+ uint64_t bytes;
+ long long int used;
+};
+
+static void
+push_resubmit(struct action_xlate_ctx *ctx, struct rule_dpif *rule)
+{
+ struct ofproto_push *push = CONTAINER_OF(ctx, struct ofproto_push, ctx);
+
+ if (rule) {
+ rule->packet_count += push->packets;
+ rule->byte_count += push->bytes;
+ rule->used = MAX(push->used, rule->used);
+ }
+}
+
+/* Pushes flow statistics to the rules which 'flow' resubmits into given
+ * 'rule''s actions and mirrors. */
+static void
+flow_push_stats(const struct rule_dpif *rule,
+ const struct flow *flow, uint64_t packets, uint64_t bytes,
+ long long int used)
+{
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
+ struct ofproto_push push;
+
+ push.packets = packets;
+ push.bytes = bytes;
+ push.used = used;
+
+ action_xlate_ctx_init(&push.ctx, ofproto, flow, flow->vlan_tci,
+ rule->up.flow_cookie, NULL);
+ push.ctx.resubmit_hook = push_resubmit;
+ ofpbuf_delete(xlate_actions(&push.ctx,
+ rule->up.actions, rule->up.n_actions));
+}
+\f
+/* Subfacets. */
+
+static struct subfacet *
+subfacet_find__(struct ofproto_dpif *ofproto,
+ const struct nlattr *key, size_t key_len, uint32_t key_hash,
+ const struct flow *flow)
+{
+ struct subfacet *subfacet;
+
+ HMAP_FOR_EACH_WITH_HASH (subfacet, hmap_node, key_hash,
+ &ofproto->subfacets) {
+ if (subfacet->key
+ ? (subfacet->key_len == key_len
+ && !memcmp(key, subfacet->key, key_len))
+ : flow_equal(flow, &subfacet->facet->flow)) {
+ return subfacet;
+ }
+ }
+
+ return NULL;
+}
+
+/* Searches 'facet' (within 'ofproto') for a subfacet with the specified
+ * 'key_fitness', 'key', and 'key_len'. Returns the existing subfacet if
+ * there is one, otherwise creates and returns a new subfacet.
+ *
+ * If the returned subfacet is new, then subfacet->actions will be NULL, in
+ * which case the caller must populate the actions with
+ * 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)
+{
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
+ uint32_t key_hash = odp_flow_key_hash(key, key_len);
+ struct subfacet *subfacet;
+
+ subfacet = subfacet_find__(ofproto, key, key_len, key_hash, &facet->flow);
+ if (subfacet) {
+ if (subfacet->facet == facet) {
+ return subfacet;
+ }
+
+ /* This shouldn't happen. */
+ VLOG_ERR_RL(&rl, "subfacet with wrong facet");
+ subfacet_destroy(subfacet);
+ }
+
+ subfacet = xzalloc(sizeof *subfacet);
+ hmap_insert(&ofproto->subfacets, &subfacet->hmap_node, key_hash);
+ list_push_back(&facet->subfacets, &subfacet->list_node);
+ subfacet->facet = facet;
+ subfacet->used = time_msec();
+ subfacet->key_fitness = key_fitness;
+ if (key_fitness != ODP_FIT_PERFECT) {
+ subfacet->key = xmemdup(key, key_len);
+ subfacet->key_len = key_len;
+ }
+ subfacet->installed = false;
+ subfacet->initial_tci = initial_tci;
+
+ return subfacet;
+}
+
+/* Searches 'ofproto' for a subfacet with the given 'key', 'key_len', and
+ * 'flow'. Returns the subfacet if one exists, otherwise NULL. */
+static struct subfacet *
+subfacet_find(struct ofproto_dpif *ofproto,
+ const struct nlattr *key, size_t key_len)
+{
+ uint32_t key_hash = odp_flow_key_hash(key, key_len);
+ enum odp_key_fitness fitness;
+ struct flow flow;
+
+ fitness = odp_flow_key_to_flow(key, key_len, &flow);
+ if (fitness == ODP_FIT_ERROR) {
+ return NULL;
+ }
+
+ return subfacet_find__(ofproto, key, key_len, key_hash, &flow);
+}
+
+/* Uninstalls 'subfacet' from the datapath, if it is installed, removes it from
+ * its facet within 'ofproto', and frees it. */
+static void
+subfacet_destroy__(struct subfacet *subfacet)
+{
+ struct facet *facet = subfacet->facet;
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
+
+ subfacet_uninstall(subfacet);
+ hmap_remove(&ofproto->subfacets, &subfacet->hmap_node);
+ list_remove(&subfacet->list_node);
+ free(subfacet->key);
+ free(subfacet->actions);
+ free(subfacet);
+}
+
+/* Destroys 'subfacet', as with subfacet_destroy__(), and then if this was the
+ * last remaining subfacet in its facet destroys the facet too. */
+static void
+subfacet_destroy(struct subfacet *subfacet)
+{
+ struct facet *facet = subfacet->facet;
+
+ if (list_is_singleton(&facet->subfacets)) {
+ /* facet_remove() needs at least one subfacet (it will remove it). */
+ facet_remove(facet);
+ } else {
+ subfacet_destroy__(subfacet);
+ }
+}
+
+/* Initializes 'key' with the sequence of OVS_KEY_ATTR_* Netlink attributes
+ * that can be used to refer to 'subfacet'. The caller must provide 'keybuf'
+ * for use as temporary storage. */
+static void
+subfacet_get_key(struct subfacet *subfacet, struct odputil_keybuf *keybuf,
+ struct ofpbuf *key)
+{
+ if (!subfacet->key) {
+ ofpbuf_use_stack(key, keybuf, sizeof *keybuf);
+ odp_flow_key_from_flow(key, &subfacet->facet->flow);
+ } else {
+ ofpbuf_use_const(key, subfacet->key, subfacet->key_len);
+ }
+}
+
+/* Composes the datapath actions for 'subfacet' based on its rule's actions. */
+static void
+subfacet_make_actions(struct subfacet *subfacet, const struct ofpbuf *packet)
+{
+ struct facet *facet = subfacet->facet;
+ const struct rule_dpif *rule = facet->rule;
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
+ struct ofpbuf *odp_actions;
+ struct action_xlate_ctx ctx;
+
+ action_xlate_ctx_init(&ctx, ofproto, &facet->flow, subfacet->initial_tci,
+ rule->up.flow_cookie, packet);
+ odp_actions = xlate_actions(&ctx, rule->up.actions, rule->up.n_actions);
+ facet->tags = ctx.tags;
+ facet->may_install = ctx.may_set_up_flow;
+ facet->has_learn = ctx.has_learn;
+ facet->has_normal = ctx.has_normal;
+ facet->nf_flow.output_iface = ctx.nf_output_iface;
+ facet->mirrors = ctx.mirrors;
+
+ if (subfacet->actions_len != odp_actions->size
+ || memcmp(subfacet->actions, odp_actions->data, odp_actions->size)) {
+ free(subfacet->actions);
+ subfacet->actions_len = odp_actions->size;
+ subfacet->actions = xmemdup(odp_actions->data, odp_actions->size);