-static void
-rule_execute(struct ofproto *ofproto, struct rule *rule, uint16_t in_port,
- struct ofpbuf *packet)
-{
- struct action_xlate_ctx ctx;
- struct facet *facet;
- struct flow flow;
- size_t size;
-
- assert(ofpbuf_headroom(packet) >= sizeof(struct ofp_packet_in));
-
- flow_extract(packet, 0, in_port, &flow);
-
- /* First look for a related facet. If we find one, account it to that. */
- facet = facet_lookup_valid(ofproto, &flow);
- if (facet && facet->rule == rule) {
- facet_execute(ofproto, facet, packet);
- return;
- }
-
- /* Otherwise, if 'rule' is in fact the correct rule for 'packet', then
- * create a new facet for it and use that. */
- if (rule_lookup(ofproto, &flow) == rule) {
- facet = facet_create(ofproto, rule, &flow, packet);
- facet_execute(ofproto, facet, packet);
- facet_install(ofproto, facet, true);
- return;
- }
-
- /* We can't account anything to a facet. If we were to try, then that
- * facet would have a non-matching rule, busting our invariants. */
- action_xlate_ctx_init(&ctx, ofproto, &flow, packet);
- if (xlate_actions(&ctx, rule->actions, rule->n_actions)) {
- ofpbuf_delete(packet);
- return;
- }
-
- size = packet->size;
- if (execute_odp_actions(ofproto, in_port,
- ctx.out.actions, ctx.out.n_actions, packet)) {
- rule->used = time_msec();
- rule->packet_count++;
- rule->byte_count += size;
- }
-}
-
-/* Inserts 'rule' into 'p''s flow table. */
-static void
-rule_insert(struct ofproto *p, struct rule *rule)
-{
- struct rule *displaced_rule;
-
- displaced_rule = rule_from_cls_rule(classifier_insert(&p->cls, &rule->cr));
- if (displaced_rule) {
- rule_destroy(p, displaced_rule);
- }
- p->need_revalidate = true;
-}
-
-/* Creates and returns a new facet within 'ofproto' owned by 'rule', given a
- * 'flow' and an example 'packet' within that flow.
- *
- * The caller must already have determined that no facet with an identical
- * 'flow' exists in 'ofproto' and that 'flow' is the best match for 'rule' in
- * 'ofproto''s classifier table. */
-static struct facet *
-facet_create(struct ofproto *ofproto, struct rule *rule,
- const struct flow *flow, const struct ofpbuf *packet)
-{
- struct facet *facet;
-
- facet = xzalloc(sizeof *facet);
- facet->used = time_msec();
- hmap_insert(&ofproto->facets, &facet->hmap_node, flow_hash(flow, 0));
- list_push_back(&rule->facets, &facet->list_node);
- facet->rule = rule;
- facet->flow = *flow;
- netflow_flow_init(&facet->nf_flow);
- netflow_flow_update_time(ofproto->netflow, &facet->nf_flow, facet->used);
-
- facet_make_actions(ofproto, facet, packet);
-
- return facet;
-}
-
-static void
-facet_free(struct facet *facet)
-{
- free(facet->actions);
- free(facet);
-}
-
-/* Remove 'rule' from 'ofproto' and free up the associated memory:
- *
- * - Removes 'rule' from the classifier.
- *
- * - If 'rule' has facets, revalidates them (and possibly uninstalls and
- * destroys them), via rule_destroy().
- */
-static void
-rule_remove(struct ofproto *ofproto, struct rule *rule)
-{
- COVERAGE_INC(ofproto_del_rule);
- ofproto->need_revalidate = true;
- classifier_remove(&ofproto->cls, &rule->cr);
- rule_destroy(ofproto, rule);
-}
-
-/* Remove 'facet' from 'ofproto' and free up the associated memory:
- *
- * - If 'facet' was installed in the datapath, uninstalls it and updates its
- * rule's statistics, via facet_uninstall().
- *
- * - Removes 'facet' from its rule and from ofproto->facets.
- */
-static void
-facet_remove(struct ofproto *ofproto, struct facet *facet)
-{
- facet_uninstall(ofproto, facet);
- facet_flush_stats(ofproto, facet);
- hmap_remove(&ofproto->facets, &facet->hmap_node);
- list_remove(&facet->list_node);
- facet_free(facet);
-}
-
-/* Composes the ODP actions for 'facet' based on its rule's actions. */
-static void
-facet_make_actions(struct ofproto *p, struct facet *facet,
- const struct ofpbuf *packet)
-{
- const struct rule *rule = facet->rule;
- struct action_xlate_ctx ctx;
- size_t actions_len;
-
- action_xlate_ctx_init(&ctx, p, &facet->flow, packet);
- xlate_actions(&ctx, rule->actions, rule->n_actions);
- facet->tags = ctx.tags;
- facet->may_install = ctx.may_set_up_flow;
- facet->nf_flow.output_iface = ctx.nf_output_iface;
-
- actions_len = ctx.out.n_actions * sizeof *ctx.out.actions;
- if (facet->n_actions != ctx.out.n_actions
- || memcmp(facet->actions, ctx.out.actions, actions_len)) {
- free(facet->actions);
- facet->n_actions = ctx.out.n_actions;
- facet->actions = xmemdup(ctx.out.actions, actions_len);
- }
-}
-
-static int
-facet_put__(struct ofproto *ofproto, struct facet *facet, int flags,
- 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 = facet->actions;
- put->flow.n_actions = facet->n_actions;
- put->flow.flags = 0;
- put->flags = flags;
- return dpif_flow_put(ofproto->dpif, put);
-}
-
-/* If 'facet' is installable, inserts or re-inserts it into 'p''s datapath. If
- * 'zero_stats' is true, clears any existing statistics from the datapath for
- * 'facet'. */
-static void
-facet_install(struct ofproto *p, struct facet *facet, bool zero_stats)
-{
- if (facet->may_install) {
- struct odp_flow_put put;
- int flags;
-
- flags = ODPPF_CREATE | ODPPF_MODIFY;
- if (zero_stats) {
- flags |= ODPPF_ZERO_STATS;
- }
- if (!facet_put__(p, facet, flags, &put)) {
- facet->installed = true;
- }
- }
-}
-
-/* Ensures that the bytes in 'facet', plus 'extra_bytes', have been passed up
- * to the accounting hook function in the ofhooks structure. */
-static void
-facet_account(struct ofproto *ofproto,
- struct facet *facet, uint64_t extra_bytes)
-{
- uint64_t total_bytes = facet->byte_count + extra_bytes;
-
- if (ofproto->ofhooks->account_flow_cb
- && total_bytes > facet->accounted_bytes)
- {
- ofproto->ofhooks->account_flow_cb(
- &facet->flow, facet->tags, facet->actions, facet->n_actions,
- total_bytes - facet->accounted_bytes, ofproto->aux);
- facet->accounted_bytes = total_bytes;
- }
-}
-
-/* If 'rule' is installed in the datapath, uninstalls it. */
-static void
-facet_uninstall(struct ofproto *p, struct facet *facet)
-{
- if (facet->installed) {
- struct odp_flow odp_flow;
-
- odp_flow_key_from_flow(&odp_flow.key, &facet->flow);
- odp_flow.actions = NULL;
- odp_flow.n_actions = 0;
- odp_flow.flags = 0;
- if (!dpif_flow_del(p->dpif, &odp_flow)) {
- facet_update_stats(p, facet, &odp_flow.stats);
- }
- facet->installed = false;
- }
-}
-
-/* Returns true if the only action for 'facet' is to send to the controller.
- * (We don't report NetFlow expiration messages for such facets because they
- * are just part of the control logic for the network, not real traffic). */
-static bool
-facet_is_controller_flow(struct facet *facet)
-{
- return (facet
- && facet->rule->n_actions == 1
- && action_outputs_to_port(&facet->rule->actions[0],
- htons(OFPP_CONTROLLER)));
-}
-
-/* Folds all of 'facet''s statistics into its rule. Also updates the
- * accounting ofhook and emits a NetFlow expiration if appropriate. */
-static void
-facet_flush_stats(struct ofproto *ofproto, struct facet *facet)
-{
- facet_account(ofproto, facet, 0);
-
- if (ofproto->netflow && !facet_is_controller_flow(facet)) {
- struct ofexpired expired;
- expired.flow = facet->flow;
- expired.packet_count = facet->packet_count;
- expired.byte_count = facet->byte_count;
- expired.used = facet->used;
- netflow_expire(ofproto->netflow, &facet->nf_flow, &expired);
- }
-
- facet->rule->packet_count += facet->packet_count;
- facet->rule->byte_count += facet->byte_count;
-
- /* Reset counters to prevent double counting if 'facet' ever gets
- * reinstalled. */
- facet->packet_count = 0;
- facet->byte_count = 0;
- facet->accounted_bytes = 0;
-
- netflow_flow_clear(&facet->nf_flow);
-}
-
-/* Searches 'ofproto''s table of facets for one exactly equal to 'flow'.
- * Returns it if found, otherwise a null pointer.
- *
- * The returned facet might need revalidation; use facet_lookup_valid()
- * instead if that is important. */
-static struct facet *
-facet_find(struct ofproto *ofproto, const struct flow *flow)
-{
- struct facet *facet;
-
- HMAP_FOR_EACH_WITH_HASH (facet, hmap_node, flow_hash(flow, 0),
- &ofproto->facets) {
- if (flow_equal(flow, &facet->flow)) {
- return facet;
- }
- }
-
- return NULL;
-}
-
-/* Searches 'ofproto''s table of facets for one exactly equal to 'flow'.
- * Returns it if found, otherwise a null pointer.
- *
- * The returned facet is guaranteed to be valid. */
-static struct facet *
-facet_lookup_valid(struct ofproto *ofproto, const struct flow *flow)
-{
- struct facet *facet = facet_find(ofproto, flow);
-
- /* The facet we found might not be valid, since we could be in need of
- * revalidation. If it is not valid, don't return it. */
- if (facet
- && ofproto->need_revalidate
- && !facet_revalidate(ofproto, facet)) {
- COVERAGE_INC(ofproto_invalidated);
- return NULL;
- }
-
- return facet;
-}
-
-/* Re-searches 'ofproto''s classifier for a rule matching 'facet':
- *
- * - If the rule found is different from 'facet''s current rule, moves
- * 'facet' to the new rule and recompiles its actions.
- *
- * - If the rule found is the same as 'facet''s current rule, leaves 'facet'
- * where it is and recompiles its actions anyway.
- *
- * - If there is none, destroys 'facet'.
- *
- * Returns true if 'facet' still exists, false if it has been destroyed. */
-static bool
-facet_revalidate(struct ofproto *ofproto, struct facet *facet)
-{
- struct action_xlate_ctx ctx;
- struct rule *new_rule;
- size_t actions_len;
- bool actions_changed;
-
- 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. */
- action_xlate_ctx_init(&ctx, ofproto, &facet->flow, NULL);
- xlate_actions(&ctx, new_rule->actions, new_rule->n_actions);
- actions_len = ctx.out.n_actions * sizeof *ctx.out.actions;
- actions_changed = (facet->n_actions != ctx.out.n_actions
- || memcmp(facet->actions, ctx.out.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 = ctx.out.actions;
- put.flow.n_actions = ctx.out.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->tags = ctx.tags;
- facet->nf_flow.output_iface = ctx.nf_output_iface;
- facet->may_install = ctx.may_set_up_flow;
- if (actions_changed) {
- free(facet->actions);
- facet->n_actions = ctx.out.n_actions;
- facet->actions = xmemdup(ctx.out.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);
- opp->supported = htonl(opp->supported);
- opp->peer = htonl(opp->peer);
-}
-
-static int
-handle_echo_request(struct ofconn *ofconn, const struct ofp_header *oh)
-{
- queue_tx(make_echo_reply(oh), ofconn, ofconn->reply_counter);
- return 0;
-}
-
-static int
-handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh)
-{
- struct ofp_switch_features *osf;
- struct ofpbuf *buf;
- struct ofport *port;
-
- osf = make_openflow_xid(sizeof *osf, OFPT_FEATURES_REPLY, oh->xid, &buf);
- osf->datapath_id = htonll(ofconn->ofproto->datapath_id);
- osf->n_buffers = htonl(pktbuf_capacity());
- osf->n_tables = 2;
- osf->capabilities = htonl(OFPC_FLOW_STATS | OFPC_TABLE_STATS |
- OFPC_PORT_STATS | OFPC_ARP_MATCH_IP);
- osf->actions = htonl((1u << OFPAT_OUTPUT) |
- (1u << OFPAT_SET_VLAN_VID) |
- (1u << OFPAT_SET_VLAN_PCP) |
- (1u << OFPAT_STRIP_VLAN) |
- (1u << OFPAT_SET_DL_SRC) |
- (1u << OFPAT_SET_DL_DST) |
- (1u << OFPAT_SET_NW_SRC) |
- (1u << OFPAT_SET_NW_DST) |
- (1u << OFPAT_SET_NW_TOS) |
- (1u << OFPAT_SET_TP_SRC) |
- (1u << OFPAT_SET_TP_DST) |
- (1u << OFPAT_ENQUEUE));
-
- HMAP_FOR_EACH (port, hmap_node, &ofconn->ofproto->ports) {
- hton_ofp_phy_port(ofpbuf_put(buf, &port->opp, sizeof port->opp));
- }
-
- queue_tx(buf, ofconn, ofconn->reply_counter);
- return 0;
-}
-
-static int
-handle_get_config_request(struct ofconn *ofconn, const struct ofp_header *oh)
-{
- struct ofpbuf *buf;
- struct ofp_switch_config *osc;
- uint16_t flags;
- bool drop_frags;
-
- /* Figure out flags. */
- dpif_get_drop_frags(ofconn->ofproto->dpif, &drop_frags);
- flags = drop_frags ? OFPC_FRAG_DROP : OFPC_FRAG_NORMAL;
-
- /* Send reply. */
- osc = make_openflow_xid(sizeof *osc, OFPT_GET_CONFIG_REPLY, oh->xid, &buf);
- osc->flags = htons(flags);
- osc->miss_send_len = htons(ofconn->miss_send_len);
- queue_tx(buf, ofconn, ofconn->reply_counter);
-
- return 0;
-}
-