+ /* Calculate new ODP actions.
+ *
+ * We are very cautious about actually modifying 'facet' state at this
+ * point, because we might need to, e.g., emit a NetFlow expiration and, if
+ * so, we need to have the old state around to properly compose it. */
+ xlate_actions(new_rule->actions, new_rule->n_actions, &facet->flow,
+ ofproto, NULL, &a, &facet->tags, &facet->may_install,
+ &new_nf_output_iface);
+ actions_len = a.n_actions * sizeof *a.actions;
+ actions_changed = (facet->n_actions != a.n_actions
+ || memcmp(facet->actions, a.actions, actions_len));
+
+ /* If the ODP actions changed or the installability changed, then we need
+ * to talk to the datapath. */
+ if (actions_changed || facet->may_install != facet->installed) {
+ if (facet->may_install) {
+ struct odp_flow_put put;
+
+ memset(&put.flow.stats, 0, sizeof put.flow.stats);
+ odp_flow_key_from_flow(&put.flow.key, &facet->flow);
+ put.flow.actions = a.actions;
+ put.flow.n_actions = a.n_actions;
+ put.flow.flags = 0;
+ put.flags = ODPPF_CREATE | ODPPF_MODIFY | ODPPF_ZERO_STATS;
+ dpif_flow_put(ofproto->dpif, &put);
+
+ facet_update_stats(ofproto, facet, &put.flow.stats);
+ } else {
+ facet_uninstall(ofproto, facet);
+ }
+
+ /* The datapath flow is gone or has zeroed stats, so push stats out of
+ * 'facet' into 'rule'. */
+ facet_flush_stats(ofproto, facet);
+ }
+
+ /* Update 'facet' now that we've taken care of all the old state. */
+ facet->nf_flow.output_iface = new_nf_output_iface;
+ if (actions_changed) {
+ free(facet->actions);
+ facet->n_actions = a.n_actions;
+ facet->actions = xmemdup(a.actions, actions_len);
+ }
+ if (facet->rule != new_rule) {