+ COVERAGE_INC(facet_revalidate);
+
+ /* Determine the new rule. */
+ new_rule = rule_lookup(ofproto, &facet->flow);
+ if (!new_rule) {
+ /* No new rule, so delete the facet. */
+ facet_remove(ofproto, facet);
+ return false;
+ }
+
+ /* 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) {
+ COVERAGE_INC(facet_changed_rule);
+ list_remove(&facet->list_node);
+ list_push_back(&new_rule->facets, &facet->list_node);
+ facet->rule = new_rule;
+ facet->used = new_rule->created;
+ }
+
+ return true;
+}
+\f
+static void
+queue_tx(struct ofpbuf *msg, const struct ofconn *ofconn,
+ struct rconn_packet_counter *counter)
+{
+ update_openflow_length(msg);
+ if (rconn_send(ofconn->rconn, msg, counter)) {
+ ofpbuf_delete(msg);
+ }
+}
+
+static void
+send_error_oh(const struct ofconn *ofconn, const struct ofp_header *oh,
+ int error)
+{
+ struct ofpbuf *buf = make_ofp_error_msg(error, oh);
+ if (buf) {
+ COVERAGE_INC(ofproto_error);
+ queue_tx(buf, ofconn, ofconn->reply_counter);
+ }
+}
+
+static void
+hton_ofp_phy_port(struct ofp_phy_port *opp)
+{
+ opp->port_no = htons(opp->port_no);
+ opp->config = htonl(opp->config);
+ opp->state = htonl(opp->state);
+ opp->curr = htonl(opp->curr);
+ opp->advertised = htonl(opp->advertised);