-/* If 'rule' is installed in the datapath, uninstalls it. */
-static void
-facet_uninstall(struct ofproto *p, struct facet *facet)
-{
- if (facet->installed) {
- struct odputil_keybuf keybuf;
- struct dpif_flow_stats stats;
- struct ofpbuf key;
- int error;
-
- ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
- odp_flow_key_from_flow(&key, &facet->flow);
-
- error = dpif_flow_del(p->dpif, key.data, key.size, &stats);
- facet_reset_dp_stats(facet, &stats);
- if (!error) {
- facet_update_stats(p, facet, &stats);
- }
-
- facet->installed = false;
- } else {
- assert(facet->dp_packet_count == 0);
- assert(facet->dp_byte_count == 0);
- }
-}
-
-/* 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)));
-}
-
-/* Resets 'facet''s datapath statistics counters. This should be called when
- * 'facet''s statistics are cleared in the datapath. If 'stats' is non-null,
- * it should contain the statistics returned by dpif when 'facet' was reset in
- * the datapath. 'stats' will be modified to only included statistics new
- * since 'facet' was last updated. */
-static void
-facet_reset_dp_stats(struct facet *facet, struct dpif_flow_stats *stats)
-{
- if (stats && facet->dp_packet_count <= stats->n_packets
- && facet->dp_byte_count <= stats->n_bytes) {
- stats->n_packets -= facet->dp_packet_count;
- stats->n_bytes -= facet->dp_byte_count;
- }
-
- facet->dp_packet_count = 0;
- facet->dp_byte_count = 0;
-}
-
-/* Folds all of 'facet''s statistics into its rule. Also updates the
- * accounting ofhook and emits a NetFlow expiration if appropriate. All of
- * 'facet''s statistics in the datapath should have been zeroed and folded into
- * its packet and byte counts before this function is called. */
-static void
-facet_flush_stats(struct ofproto *ofproto, struct facet *facet)
-{
- assert(!facet->dp_byte_count);
- assert(!facet->dp_packet_count);
-
- facet_push_stats(ofproto, 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->rs_packet_count = 0;
- facet->rs_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 ofpbuf *odp_actions;
- struct rule *new_rule;
- 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 do not modify any 'facet' state yet, 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);
- odp_actions = xlate_actions(&ctx, new_rule->actions, new_rule->n_actions);
- actions_changed = (facet->actions_len != odp_actions->size
- || memcmp(facet->actions, odp_actions->data,
- facet->actions_len));
-
- /* If the ODP actions changed or the installability changed, then we need
- * to talk to the datapath. */
- if (actions_changed || ctx.may_set_up_flow != facet->installed) {
- if (ctx.may_set_up_flow) {
- struct dpif_flow_stats stats;
-
- facet_put__(ofproto, facet,
- odp_actions->data, odp_actions->size, &stats);
- facet_update_stats(ofproto, facet, &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->actions_len = odp_actions->size;
- facet->actions = xmemdup(odp_actions->data, odp_actions->size);
- }
- 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;
- facet->rs_used = facet->used;
- }
-
- ofpbuf_delete(odp_actions);
-
- return true;
-}
-\f
-static void
-send_error_oh(const struct ofconn *ofconn, const struct ofp_header *oh,
- int error)
-{
- struct ofpbuf *buf = ofputil_encode_error_msg(error, oh);
- if (buf) {
- COVERAGE_INC(ofproto_error);
- ofconn_send_reply(ofconn, buf);
- }
-}
-
-static int
-handle_echo_request(struct ofconn *ofconn, const struct ofp_header *oh)
-{
- ofconn_send_reply(ofconn, make_echo_reply(oh));
- return 0;
-}
-
-static int
-handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh)
-{
- struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
- 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(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, &ofproto->ports) {
- ofpbuf_put(buf, &port->opp, sizeof port->opp);
- }
-
- ofconn_send_reply(ofconn, buf);
- return 0;
-}
-
-static int
-handle_get_config_request(struct ofconn *ofconn, const struct ofp_header *oh)
-{
- struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
- struct ofpbuf *buf;
- struct ofp_switch_config *osc;
- uint16_t flags;
- bool drop_frags;
-
- /* Figure out flags. */
- dpif_get_drop_frags(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_get_miss_send_len(ofconn));
- ofconn_send_reply(ofconn, buf);
-
- return 0;
-}
-
-static int
-handle_set_config(struct ofconn *ofconn, const struct ofp_switch_config *osc)
-{
- struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
- uint16_t flags = ntohs(osc->flags);
-
- if (ofconn_get_type(ofconn) == OFCONN_PRIMARY
- && ofconn_get_role(ofconn) != NX_ROLE_SLAVE) {
- switch (flags & OFPC_FRAG_MASK) {
- case OFPC_FRAG_NORMAL:
- dpif_set_drop_frags(ofproto->dpif, false);
- break;
- case OFPC_FRAG_DROP:
- dpif_set_drop_frags(ofproto->dpif, true);
- break;
- default:
- VLOG_WARN_RL(&rl, "requested bad fragment mode (flags=%"PRIx16")",
- osc->flags);
- break;
- }
- }
-
- ofconn_set_miss_send_len(ofconn, ntohs(osc->miss_send_len));
-
- return 0;
-}
-
-static void do_xlate_actions(const union ofp_action *in, size_t n_in,
- struct action_xlate_ctx *ctx);
-
-static void
-add_output_action(struct action_xlate_ctx *ctx, uint16_t port)
-{
- const struct ofport *ofport = get_port(ctx->ofproto, port);
-
- if (ofport) {
- if (ofport->opp.config & htonl(OFPPC_NO_FWD)) {
- /* Forwarding disabled on port. */
- return;
- }
- } else {
- /*
- * We don't have an ofport record for this port, but it doesn't hurt to
- * allow forwarding to it anyhow. Maybe such a port will appear later
- * and we're pre-populating the flow table.
- */
- }
-
- nl_msg_put_u32(ctx->odp_actions, ODP_ACTION_ATTR_OUTPUT, port);
- ctx->nf_output_iface = port;
-}
-
-static struct rule *
-rule_lookup(struct ofproto *ofproto, const struct flow *flow)
-{
- return rule_from_cls_rule(classifier_lookup(&ofproto->cls, flow));
-}
-
-static void
-xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port)
-{
- if (ctx->recurse < MAX_RESUBMIT_RECURSION) {
- uint16_t old_in_port;
- struct rule *rule;
-
- /* Look up a flow with 'in_port' as the input port. Then restore the
- * original input port (otherwise OFPP_NORMAL and OFPP_IN_PORT will
- * have surprising behavior). */
- old_in_port = ctx->flow.in_port;
- ctx->flow.in_port = in_port;
- rule = rule_lookup(ctx->ofproto, &ctx->flow);
- ctx->flow.in_port = old_in_port;
-
- if (ctx->resubmit_hook) {
- ctx->resubmit_hook(ctx, rule);
- }
-
- if (rule) {
- ctx->recurse++;
- do_xlate_actions(rule->actions, rule->n_actions, ctx);
- ctx->recurse--;
- }
- } else {
- static struct vlog_rate_limit recurse_rl = VLOG_RATE_LIMIT_INIT(1, 1);
-
- VLOG_ERR_RL(&recurse_rl, "NXAST_RESUBMIT recursed over %d times",
- MAX_RESUBMIT_RECURSION);
- }
-}
-
-static void
-flood_packets(struct ofproto *ofproto, uint16_t odp_in_port, ovs_be32 mask,
- uint16_t *nf_output_iface, struct ofpbuf *odp_actions)
-{
- struct ofport *ofport;
-
- HMAP_FOR_EACH (ofport, hmap_node, &ofproto->ports) {
- uint16_t odp_port = ofport->odp_port;
- if (odp_port != odp_in_port && !(ofport->opp.config & mask)) {
- nl_msg_put_u32(odp_actions, ODP_ACTION_ATTR_OUTPUT, odp_port);
- }
- }
- *nf_output_iface = NF_OUT_FLOOD;
-}
-
-static void
-xlate_output_action__(struct action_xlate_ctx *ctx,
- uint16_t port, uint16_t max_len)
-{
- uint16_t odp_port;
- uint16_t prev_nf_output_iface = ctx->nf_output_iface;
-
- ctx->nf_output_iface = NF_OUT_DROP;
-
- switch (port) {
- case OFPP_IN_PORT:
- add_output_action(ctx, ctx->flow.in_port);
- break;
- case OFPP_TABLE:
- xlate_table_action(ctx, ctx->flow.in_port);
- break;
- case OFPP_NORMAL:
- if (!ctx->ofproto->ofhooks->normal_cb(&ctx->flow, ctx->packet,
- ctx->odp_actions, &ctx->tags,
- &ctx->nf_output_iface,
- ctx->ofproto->aux)) {
- COVERAGE_INC(ofproto_uninstallable);
- ctx->may_set_up_flow = false;
- }
- break;
- case OFPP_FLOOD:
- flood_packets(ctx->ofproto, ctx->flow.in_port, htonl(OFPPC_NO_FLOOD),
- &ctx->nf_output_iface, ctx->odp_actions);
- break;
- case OFPP_ALL:
- flood_packets(ctx->ofproto, ctx->flow.in_port, htonl(0),
- &ctx->nf_output_iface, ctx->odp_actions);
- break;
- case OFPP_CONTROLLER:
- nl_msg_put_u64(ctx->odp_actions, ODP_ACTION_ATTR_CONTROLLER, max_len);
- break;
- case OFPP_LOCAL:
- add_output_action(ctx, ODPP_LOCAL);
- break;
- default:
- odp_port = ofp_port_to_odp_port(port);
- if (odp_port != ctx->flow.in_port) {
- add_output_action(ctx, odp_port);
- }
- break;
- }
-
- if (prev_nf_output_iface == NF_OUT_FLOOD) {
- ctx->nf_output_iface = NF_OUT_FLOOD;
- } else if (ctx->nf_output_iface == NF_OUT_DROP) {
- ctx->nf_output_iface = prev_nf_output_iface;
- } else if (prev_nf_output_iface != NF_OUT_DROP &&
- ctx->nf_output_iface != NF_OUT_FLOOD) {
- ctx->nf_output_iface = NF_OUT_MULTI;
- }
-}
-
-static void
-xlate_output_action(struct action_xlate_ctx *ctx,
- const struct ofp_action_output *oao)
-{
- xlate_output_action__(ctx, ntohs(oao->port), ntohs(oao->max_len));
-}
-
-/* If the final ODP action in 'ctx' is "pop priority", drop it, as an
- * optimization, because we're going to add another action that sets the
- * priority immediately after, or because there are no actions following the
- * pop. */
-static void
-remove_pop_action(struct action_xlate_ctx *ctx)
-{
- if (ctx->odp_actions->size == ctx->last_pop_priority) {
- ctx->odp_actions->size -= NLA_ALIGN(NLA_HDRLEN);
- ctx->last_pop_priority = -1;
- }
-}
-
-static void
-add_pop_action(struct action_xlate_ctx *ctx)
-{
- if (ctx->odp_actions->size != ctx->last_pop_priority) {
- nl_msg_put_flag(ctx->odp_actions, ODP_ACTION_ATTR_POP_PRIORITY);
- ctx->last_pop_priority = ctx->odp_actions->size;
- }
-}
-
-static void
-xlate_enqueue_action(struct action_xlate_ctx *ctx,
- const struct ofp_action_enqueue *oae)
-{
- uint16_t ofp_port, odp_port;
- uint32_t priority;
- int error;
-
- error = dpif_queue_to_priority(ctx->ofproto->dpif, ntohl(oae->queue_id),
- &priority);
- if (error) {
- /* Fall back to ordinary output action. */
- xlate_output_action__(ctx, ntohs(oae->port), 0);
- return;
- }
-
- /* Figure out ODP output port. */
- ofp_port = ntohs(oae->port);
- if (ofp_port != OFPP_IN_PORT) {
- odp_port = ofp_port_to_odp_port(ofp_port);
- } else {
- odp_port = ctx->flow.in_port;
- }
-
- /* Add ODP actions. */
- remove_pop_action(ctx);
- nl_msg_put_u32(ctx->odp_actions, ODP_ACTION_ATTR_SET_PRIORITY, priority);
- add_output_action(ctx, odp_port);
- add_pop_action(ctx);
-
- /* Update NetFlow output port. */
- if (ctx->nf_output_iface == NF_OUT_DROP) {
- ctx->nf_output_iface = odp_port;
- } else if (ctx->nf_output_iface != NF_OUT_FLOOD) {
- ctx->nf_output_iface = NF_OUT_MULTI;
- }
-}
-
-static void
-xlate_set_queue_action(struct action_xlate_ctx *ctx,
- const struct nx_action_set_queue *nasq)
-{
- uint32_t priority;
- int error;
-
- error = dpif_queue_to_priority(ctx->ofproto->dpif, ntohl(nasq->queue_id),
- &priority);
- if (error) {
- /* Couldn't translate queue to a priority, so ignore. A warning
- * has already been logged. */
- return;
- }
-
- remove_pop_action(ctx);
- nl_msg_put_u32(ctx->odp_actions, ODP_ACTION_ATTR_SET_PRIORITY, priority);
-}
-
-static void
-xlate_set_dl_tci(struct action_xlate_ctx *ctx)
-{
- ovs_be16 tci = ctx->flow.vlan_tci;
- if (!(tci & htons(VLAN_CFI))) {
- nl_msg_put_flag(ctx->odp_actions, ODP_ACTION_ATTR_STRIP_VLAN);
- } else {
- nl_msg_put_be16(ctx->odp_actions, ODP_ACTION_ATTR_SET_DL_TCI,
- tci & ~htons(VLAN_CFI));
- }
-}
-
-struct xlate_reg_state {
- ovs_be16 vlan_tci;
- ovs_be64 tun_id;
-};
-
-static void
-save_reg_state(const struct action_xlate_ctx *ctx,
- struct xlate_reg_state *state)
-{
- state->vlan_tci = ctx->flow.vlan_tci;
- state->tun_id = ctx->flow.tun_id;
-}
-
-static void
-update_reg_state(struct action_xlate_ctx *ctx,
- const struct xlate_reg_state *state)
-{
- if (ctx->flow.vlan_tci != state->vlan_tci) {
- xlate_set_dl_tci(ctx);
- }
- if (ctx->flow.tun_id != state->tun_id) {
- nl_msg_put_be64(ctx->odp_actions,
- ODP_ACTION_ATTR_SET_TUNNEL, ctx->flow.tun_id);
- }
-}
-
-static void
-xlate_nicira_action(struct action_xlate_ctx *ctx,
- const struct nx_action_header *nah)
-{
- const struct nx_action_resubmit *nar;
- const struct nx_action_set_tunnel *nast;
- const struct nx_action_set_queue *nasq;
- const struct nx_action_multipath *nam;
- const struct nx_action_autopath *naa;
- enum nx_action_subtype subtype = ntohs(nah->subtype);
- const struct ofhooks *ofhooks = ctx->ofproto->ofhooks;
- struct xlate_reg_state state;
- uint16_t autopath_port;
- ovs_be64 tun_id;
-
- assert(nah->vendor == htonl(NX_VENDOR_ID));
- switch (subtype) {
- case NXAST_RESUBMIT:
- nar = (const struct nx_action_resubmit *) nah;
- xlate_table_action(ctx, ofp_port_to_odp_port(ntohs(nar->in_port)));
- break;
-
- case NXAST_SET_TUNNEL:
- nast = (const struct nx_action_set_tunnel *) nah;
- tun_id = htonll(ntohl(nast->tun_id));
- nl_msg_put_be64(ctx->odp_actions, ODP_ACTION_ATTR_SET_TUNNEL, tun_id);
- ctx->flow.tun_id = tun_id;
- break;
-
- case NXAST_DROP_SPOOFED_ARP:
- if (ctx->flow.dl_type == htons(ETH_TYPE_ARP)) {
- nl_msg_put_flag(ctx->odp_actions,
- ODP_ACTION_ATTR_DROP_SPOOFED_ARP);
- }
- break;
-
- case NXAST_SET_QUEUE:
- nasq = (const struct nx_action_set_queue *) nah;
- xlate_set_queue_action(ctx, nasq);
- break;
-
- case NXAST_POP_QUEUE:
- add_pop_action(ctx);
- break;
-
- case NXAST_REG_MOVE:
- save_reg_state(ctx, &state);
- nxm_execute_reg_move((const struct nx_action_reg_move *) nah,
- &ctx->flow);
- update_reg_state(ctx, &state);
- break;
-
- case NXAST_REG_LOAD:
- save_reg_state(ctx, &state);
- nxm_execute_reg_load((const struct nx_action_reg_load *) nah,
- &ctx->flow);
- update_reg_state(ctx, &state);
- break;
-
- case NXAST_NOTE:
- /* Nothing to do. */
- break;
-
- case NXAST_SET_TUNNEL64:
- tun_id = ((const struct nx_action_set_tunnel64 *) nah)->tun_id;
- nl_msg_put_be64(ctx->odp_actions, ODP_ACTION_ATTR_SET_TUNNEL, tun_id);
- ctx->flow.tun_id = tun_id;
- break;
-
- case NXAST_MULTIPATH:
- nam = (const struct nx_action_multipath *) nah;
- multipath_execute(nam, &ctx->flow);
- break;
-
- case NXAST_AUTOPATH:
- naa = (const struct nx_action_autopath *) nah;
- autopath_port = (ofhooks->autopath_cb
- ? ofhooks->autopath_cb(&ctx->flow, ntohl(naa->id),
- &ctx->tags, ctx->ofproto->aux)
- : OFPP_NONE);
- autopath_execute(naa, &ctx->flow, autopath_port);
- break;
-
- /* If you add a new action here that modifies flow data, don't forget to
- * update the flow key in ctx->flow at the same time. */
-
- case NXAST_SNAT__OBSOLETE:
- default:
- VLOG_DBG_RL(&rl, "unknown Nicira action type %d", (int) subtype);
- break;
- }
-}
-
-static void
-do_xlate_actions(const union ofp_action *in, size_t n_in,
- struct action_xlate_ctx *ctx)
-{
- struct actions_iterator iter;
- const union ofp_action *ia;
- const struct ofport *port;
-
- port = get_port(ctx->ofproto, ctx->flow.in_port);
- if (port && port->opp.config & htonl(OFPPC_NO_RECV | OFPPC_NO_RECV_STP) &&
- port->opp.config & (eth_addr_equals(ctx->flow.dl_dst, eth_addr_stp)
- ? htonl(OFPPC_NO_RECV_STP)
- : htonl(OFPPC_NO_RECV))) {
- /* Drop this flow. */
- return;
- }
-
- for (ia = actions_first(&iter, in, n_in); ia; ia = actions_next(&iter)) {
- enum ofp_action_type type = ntohs(ia->type);
- const struct ofp_action_dl_addr *oada;
-
- switch (type) {
- case OFPAT_OUTPUT:
- xlate_output_action(ctx, &ia->output);
- break;
-
- case OFPAT_SET_VLAN_VID:
- ctx->flow.vlan_tci &= ~htons(VLAN_VID_MASK);
- ctx->flow.vlan_tci |= ia->vlan_vid.vlan_vid | htons(VLAN_CFI);
- xlate_set_dl_tci(ctx);
- break;
-
- case OFPAT_SET_VLAN_PCP:
- ctx->flow.vlan_tci &= ~htons(VLAN_PCP_MASK);
- ctx->flow.vlan_tci |= htons(
- (ia->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT) | VLAN_CFI);
- xlate_set_dl_tci(ctx);
- break;
-
- case OFPAT_STRIP_VLAN:
- ctx->flow.vlan_tci = htons(0);
- xlate_set_dl_tci(ctx);
- break;
-
- case OFPAT_SET_DL_SRC:
- oada = ((struct ofp_action_dl_addr *) ia);
- nl_msg_put_unspec(ctx->odp_actions, ODP_ACTION_ATTR_SET_DL_SRC,
- oada->dl_addr, ETH_ADDR_LEN);
- memcpy(ctx->flow.dl_src, oada->dl_addr, ETH_ADDR_LEN);
- break;
-
- case OFPAT_SET_DL_DST:
- oada = ((struct ofp_action_dl_addr *) ia);
- nl_msg_put_unspec(ctx->odp_actions, ODP_ACTION_ATTR_SET_DL_DST,
- oada->dl_addr, ETH_ADDR_LEN);
- memcpy(ctx->flow.dl_dst, oada->dl_addr, ETH_ADDR_LEN);
- break;
-
- case OFPAT_SET_NW_SRC:
- nl_msg_put_be32(ctx->odp_actions, ODP_ACTION_ATTR_SET_NW_SRC,
- ia->nw_addr.nw_addr);
- ctx->flow.nw_src = ia->nw_addr.nw_addr;
- break;
-
- case OFPAT_SET_NW_DST:
- nl_msg_put_be32(ctx->odp_actions, ODP_ACTION_ATTR_SET_NW_DST,
- ia->nw_addr.nw_addr);
- ctx->flow.nw_dst = ia->nw_addr.nw_addr;
- break;
-
- case OFPAT_SET_NW_TOS:
- nl_msg_put_u8(ctx->odp_actions, ODP_ACTION_ATTR_SET_NW_TOS,
- ia->nw_tos.nw_tos);
- ctx->flow.nw_tos = ia->nw_tos.nw_tos;
- break;
-
- case OFPAT_SET_TP_SRC:
- nl_msg_put_be16(ctx->odp_actions, ODP_ACTION_ATTR_SET_TP_SRC,
- ia->tp_port.tp_port);
- ctx->flow.tp_src = ia->tp_port.tp_port;
- break;
-
- case OFPAT_SET_TP_DST:
- nl_msg_put_be16(ctx->odp_actions, ODP_ACTION_ATTR_SET_TP_DST,
- ia->tp_port.tp_port);
- ctx->flow.tp_dst = ia->tp_port.tp_port;
- break;
-
- case OFPAT_VENDOR:
- xlate_nicira_action(ctx, (const struct nx_action_header *) ia);
- break;
-
- case OFPAT_ENQUEUE:
- xlate_enqueue_action(ctx, (const struct ofp_action_enqueue *) ia);
- break;
-
- default:
- VLOG_DBG_RL(&rl, "unknown action type %d", (int) type);
- break;
- }
- }
-}
-
-static void
-action_xlate_ctx_init(struct action_xlate_ctx *ctx,
- struct ofproto *ofproto, const struct flow *flow,
- const struct ofpbuf *packet)
-{
- ctx->ofproto = ofproto;
- ctx->flow = *flow;
- ctx->packet = packet;
- ctx->resubmit_hook = NULL;
- ctx->check_special = true;
-}
-
-static void
-ofproto_process_cfm(struct ofproto *ofproto, const struct flow *flow,
- const struct ofpbuf *packet)
-{
- struct ofport *ofport;
-
- ofport = get_port(ofproto, flow->in_port);
- if (ofport && ofport->cfm) {
- cfm_process_heartbeat(ofport->cfm, packet);
- }
-}
-
-static struct ofpbuf *
-xlate_actions(struct action_xlate_ctx *ctx,
- const union ofp_action *in, size_t n_in)
-{
- COVERAGE_INC(ofproto_ofp2odp);
-
- ctx->odp_actions = ofpbuf_new(512);
- ctx->tags = 0;
- ctx->may_set_up_flow = true;
- ctx->nf_output_iface = NF_OUT_DROP;
- ctx->recurse = 0;
- ctx->last_pop_priority = -1;
-
- if (ctx->check_special && cfm_should_process_flow(&ctx->flow)) {
- if (ctx->packet) {
- ofproto_process_cfm(ctx->ofproto, &ctx->flow, ctx->packet);
- }
- ctx->may_set_up_flow = false;
- } else if (ctx->check_special
- && ctx->ofproto->ofhooks->special_cb
- && !ctx->ofproto->ofhooks->special_cb(&ctx->flow, ctx->packet,
- ctx->ofproto->aux)) {
- ctx->may_set_up_flow = false;
- } else {
- do_xlate_actions(in, n_in, ctx);
- }
-
- remove_pop_action(ctx);
-
- /* Check with in-band control to see if we're allowed to set up this
- * flow. */
- if (!connmgr_may_set_up_flow(ctx->ofproto->connmgr, &ctx->flow,
- ctx->odp_actions->data,
- ctx->odp_actions->size)) {
- ctx->may_set_up_flow = false;
- }
-
- return ctx->odp_actions;
-}
-
-/* Checks whether 'ofconn' is a slave controller. If so, returns an OpenFlow
- * error message code (composed with ofp_mkerr()) for the caller to propagate
- * upward. Otherwise, returns 0.
- *
- * The log message mentions 'msg_type'. */
-static int
-reject_slave_controller(struct ofconn *ofconn, const char *msg_type)