+static void
+xlate_set_dl_tci(struct action_xlate_ctx *ctx)
+{
+ ovs_be16 tci = ctx->flow.vlan_tci;
+ if (!(tci & htons(VLAN_CFI))) {
+ odp_actions_add(ctx->out, ODPAT_STRIP_VLAN);
+ } else {
+ union odp_action *oa = odp_actions_add(ctx->out, ODPAT_SET_DL_TCI);
+ oa->dl_tci.tci = tci & ~htons(VLAN_CFI);
+ }
+}
+
+static void
+xlate_reg_move_action(struct action_xlate_ctx *ctx,
+ const struct nx_action_reg_move *narm)
+{
+ ovs_be16 old_tci = ctx->flow.vlan_tci;
+
+ nxm_execute_reg_move(narm, &ctx->flow);
+
+ if (ctx->flow.vlan_tci != old_tci) {
+ xlate_set_dl_tci(ctx);
+ }
+}
+
+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;
+ union odp_action *oa;
+ int subtype = ntohs(nah->subtype);
+
+ 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;
+ oa = odp_actions_add(ctx->out, ODPAT_SET_TUNNEL);
+ ctx->flow.tun_id = oa->tunnel.tun_id = nast->tun_id;
+ break;
+
+ case NXAST_DROP_SPOOFED_ARP:
+ if (ctx->flow.dl_type == htons(ETH_TYPE_ARP)) {
+ odp_actions_add(ctx->out, ODPAT_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:
+ odp_actions_add(ctx->out, ODPAT_POP_PRIORITY);
+ break;
+
+ case NXAST_REG_MOVE:
+ xlate_reg_move_action(ctx, (const struct nx_action_reg_move *) nah);
+ break;
+
+ case NXAST_REG_LOAD:
+ nxm_execute_reg_load((const struct nx_action_reg_load *) nah,
+ &ctx->flow);
+
+ case NXAST_NOTE:
+ /* Nothing to do. */
+ 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. */
+
+ default:
+ VLOG_DBG_RL(&rl, "unknown Nicira action type %"PRIu16, 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 & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) &&
+ port->opp.config & (eth_addr_equals(ctx->flow.dl_dst, eth_addr_stp)
+ ? OFPPC_NO_RECV_STP : OFPPC_NO_RECV)) {
+ /* Drop this flow. */
+ return;
+ }
+
+ for (ia = actions_first(&iter, in, n_in); ia; ia = actions_next(&iter)) {
+ uint16_t type = ntohs(ia->type);
+ union odp_action *oa;
+
+ 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:
+ oa = odp_actions_add(ctx->out, ODPAT_SET_DL_SRC);
+ memcpy(oa->dl_addr.dl_addr,
+ ((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
+ memcpy(ctx->flow.dl_src,
+ ((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
+ break;
+
+ case OFPAT_SET_DL_DST:
+ oa = odp_actions_add(ctx->out, ODPAT_SET_DL_DST);