Fix table checking for goto table instruction.
[sliver-openvswitch.git] / lib / ofp-actions.c
index d6fc429..899928a 100644 (file)
@@ -42,7 +42,7 @@ output_from_openflow10(const struct ofp10_action_output *oao,
     struct ofpact_output *output;
 
     output = ofpact_put_OUTPUT(out);
-    output->port = ntohs(oao->port);
+    output->port = u16_to_ofp(ntohs(oao->port));
     output->max_len = ntohs(oao->max_len);
 
     return ofputil_check_output_port(output->port, OFPP_MAX);
@@ -55,9 +55,10 @@ enqueue_from_openflow10(const struct ofp10_action_enqueue *oae,
     struct ofpact_enqueue *enqueue;
 
     enqueue = ofpact_put_ENQUEUE(out);
-    enqueue->port = ntohs(oae->port);
+    enqueue->port = u16_to_ofp(ntohs(oae->port));
     enqueue->queue = ntohl(oae->queue_id);
-    if (enqueue->port >= OFPP_MAX && enqueue->port != OFPP_IN_PORT
+    if (ofp_to_u16(enqueue->port) >= ofp_to_u16(OFPP_MAX)
+        && enqueue->port != OFPP_IN_PORT
         && enqueue->port != OFPP_LOCAL) {
         return OFPERR_OFPBAC_BAD_OUT_PORT;
     }
@@ -72,7 +73,7 @@ resubmit_from_openflow(const struct nx_action_resubmit *nar,
 
     resubmit = ofpact_put_RESUBMIT(out);
     resubmit->ofpact.compat = OFPUTIL_NXAST_RESUBMIT;
-    resubmit->in_port = ntohs(nar->in_port);
+    resubmit->in_port = u16_to_ofp(ntohs(nar->in_port));
     resubmit->table_id = 0xff;
 }
 
@@ -88,7 +89,7 @@ resubmit_table_from_openflow(const struct nx_action_resubmit *nar,
 
     resubmit = ofpact_put_RESUBMIT(out);
     resubmit->ofpact.compat = OFPUTIL_NXAST_RESUBMIT_TABLE;
-    resubmit->in_port = ntohs(nar->in_port);
+    resubmit->in_port = u16_to_ofp(ntohs(nar->in_port));
     resubmit->table_id = nar->table;
     return 0;
 }
@@ -209,14 +210,33 @@ dec_ttl_cnt_ids_from_openflow(const struct nx_action_cnt_ids *nac_ids,
     for (i = 0; i < ids->n_controllers; i++) {
         uint16_t id = ntohs(((ovs_be16 *)(nac_ids + 1))[i]);
         ofpbuf_put(out, &id, sizeof id);
+        ids = out->l2;
     }
 
-    ids = out->l2;
     ofpact_update_len(out, &ids->ofpact);
 
     return 0;
 }
 
+static enum ofperr
+sample_from_openflow(const struct nx_action_sample *nas,
+                     struct ofpbuf *out)
+{
+    struct ofpact_sample *sample;
+
+    sample = ofpact_put_SAMPLE(out);
+    sample->probability = ntohs(nas->probability);
+    sample->collector_set_id = ntohl(nas->collector_set_id);
+    sample->obs_domain_id = ntohl(nas->obs_domain_id);
+    sample->obs_point_id = ntohl(nas->obs_point_id);
+
+    if (sample->probability == 0) {
+        return OFPERR_OFPBAC_BAD_ARGUMENT;
+    }
+
+    return 0;
+}
+
 static enum ofperr
 decode_nxast_action(const union ofp_action *a, enum ofputil_action_code *code)
 {
@@ -339,6 +359,16 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
             (const struct nx_action_reg_load *) a, out);
         break;
 
+    case OFPUTIL_NXAST_STACK_PUSH:
+        error = nxm_stack_push_from_openflow(
+            (const struct nx_action_stack *) a, out);
+        break;
+
+    case OFPUTIL_NXAST_STACK_POP:
+        error = nxm_stack_pop_from_openflow(
+            (const struct nx_action_stack *) a, out);
+        break;
+
     case OFPUTIL_NXAST_NOTE:
         nan = (const struct nx_action_note *) a;
         note_from_openflow(nan, out);
@@ -406,6 +436,16 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
         break;
     }
 
+    case OFPUTIL_NXAST_SET_MPLS_TTL: {
+        struct nx_action_mpls_ttl *nxamt = (struct nx_action_mpls_ttl *)a;
+        ofpact_put_SET_MPLS_TTL(out)->ttl = nxamt->ttl;
+        break;
+    }
+
+    case OFPUTIL_NXAST_DEC_MPLS_TTL:
+        ofpact_put_DEC_MPLS_TTL(out);
+        break;
+
     case OFPUTIL_NXAST_POP_MPLS: {
         struct nx_action_pop_mpls *nxapm = (struct nx_action_pop_mpls *)a;
         if (eth_type_mpls(nxapm->ethertype)) {
@@ -414,6 +454,11 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
         ofpact_put_POP_MPLS(out)->ethertype = nxapm->ethertype;
         break;
     }
+
+    case OFPUTIL_NXAST_SAMPLE:
+        error = sample_from_openflow(
+            (const struct nx_action_sample *) a, out);
+        break;
     }
 
     return error;
@@ -786,6 +831,16 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
         return nxm_reg_load_from_openflow12_set_field(
             (const struct ofp12_action_set_field *)a, out);
 
+    case OFPUTIL_OFPAT11_SET_MPLS_TTL: {
+        struct ofp11_action_mpls_ttl *oamt = (struct ofp11_action_mpls_ttl *)a;
+        ofpact_put_SET_MPLS_TTL(out)->ttl = oamt->mpls_ttl;
+        break;
+    }
+
+    case OFPUTIL_OFPAT11_DEC_MPLS_TTL:
+        ofpact_put_DEC_MPLS_TTL(out);
+        break;
+
     case OFPUTIL_OFPAT11_PUSH_MPLS: {
         struct ofp11_action_push *oap = (struct ofp11_action_push *)a;
         if (!eth_type_mpls(oap->ethertype)) {
@@ -859,13 +914,13 @@ OVS_INSTRUCTIONS
 };
 
 const char *
-ofpact_instruction_name_from_type(enum ovs_instruction_type type)
+ovs_instruction_name_from_type(enum ovs_instruction_type type)
 {
     return inst_info[type].name;
 }
 
 int
-ofpact_instruction_type_from_name(const char *name)
+ovs_instruction_type_from_name(const char *name)
 {
     const struct instruction_type_info *p;
     for (p = inst_info; p < &inst_info[ARRAY_SIZE(inst_info)]; p++) {
@@ -876,6 +931,58 @@ ofpact_instruction_type_from_name(const char *name)
     return -1;
 }
 
+enum ovs_instruction_type
+ovs_instruction_type_from_ofpact_type(enum ofpact_type type)
+{
+    switch (type) {
+    case OFPACT_METER:
+        return OVSINST_OFPIT13_METER;
+    case OFPACT_CLEAR_ACTIONS:
+        return OVSINST_OFPIT11_CLEAR_ACTIONS;
+    case OFPACT_WRITE_METADATA:
+        return OVSINST_OFPIT11_WRITE_METADATA;
+    case OFPACT_GOTO_TABLE:
+        return OVSINST_OFPIT11_GOTO_TABLE;
+    case OFPACT_OUTPUT:
+    case OFPACT_CONTROLLER:
+    case OFPACT_ENQUEUE:
+    case OFPACT_OUTPUT_REG:
+    case OFPACT_BUNDLE:
+    case OFPACT_SET_VLAN_VID:
+    case OFPACT_SET_VLAN_PCP:
+    case OFPACT_STRIP_VLAN:
+    case OFPACT_PUSH_VLAN:
+    case OFPACT_SET_ETH_SRC:
+    case OFPACT_SET_ETH_DST:
+    case OFPACT_SET_IPV4_SRC:
+    case OFPACT_SET_IPV4_DST:
+    case OFPACT_SET_IPV4_DSCP:
+    case OFPACT_SET_L4_SRC_PORT:
+    case OFPACT_SET_L4_DST_PORT:
+    case OFPACT_REG_MOVE:
+    case OFPACT_REG_LOAD:
+    case OFPACT_STACK_PUSH:
+    case OFPACT_STACK_POP:
+    case OFPACT_DEC_TTL:
+    case OFPACT_SET_MPLS_TTL:
+    case OFPACT_DEC_MPLS_TTL:
+    case OFPACT_PUSH_MPLS:
+    case OFPACT_POP_MPLS:
+    case OFPACT_SET_TUNNEL:
+    case OFPACT_SET_QUEUE:
+    case OFPACT_POP_QUEUE:
+    case OFPACT_FIN_TIMEOUT:
+    case OFPACT_RESUBMIT:
+    case OFPACT_LEARN:
+    case OFPACT_MULTIPATH:
+    case OFPACT_NOTE:
+    case OFPACT_EXIT:
+    case OFPACT_SAMPLE:
+    default:
+        return OVSINST_OFPIT11_APPLY_ACTIONS;
+    }
+}
+
 static inline struct ofp11_instruction *
 instruction_next(const struct ofp11_instruction *inst)
 {
@@ -948,9 +1055,7 @@ decode_openflow11_instructions(const struct ofp11_instruction insts[],
         }
 
         if (out[type]) {
-            return OFPERR_OFPBAC_UNSUPPORTED_ORDER; /* No specific code for
-                                                     * a duplicate instruction
-                                                     * exist */
+            return OFPERR_ONFBIC_DUP_INSTRUCTION;
         }
         out[type] = inst;
     }
@@ -1031,6 +1136,16 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
         goto exit;
     }
 
+    if (insts[OVSINST_OFPIT13_METER]) {
+        const struct ofp13_instruction_meter *oim;
+        struct ofpact_meter *om;
+
+        oim = (const struct ofp13_instruction_meter *)
+            insts[OVSINST_OFPIT13_METER];
+
+        om = ofpact_put_METER(ofpacts);
+        om->meter_id = ntohl(oim->meter_id);
+    }
     if (insts[OVSINST_OFPIT11_APPLY_ACTIONS]) {
         const union ofp_action *actions;
         size_t n_actions;
@@ -1082,9 +1197,10 @@ exit:
     return error;
 }
 \f
+/* May modify flow->dl_type, caller must restore it. */
 static enum ofperr
-ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports,
-               ovs_be16 *dl_type)
+ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports,
+               uint8_t table_id)
 {
     const struct ofpact_enqueue *enqueue;
 
@@ -1098,7 +1214,8 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports,
 
     case OFPACT_ENQUEUE:
         enqueue = ofpact_get_ENQUEUE(a);
-        if (enqueue->port >= max_ports && enqueue->port != OFPP_IN_PORT
+        if (ofp_to_u16(enqueue->port) >= ofp_to_u16(max_ports)
+            && enqueue->port != OFPP_IN_PORT
             && enqueue->port != OFPP_LOCAL) {
             return OFPERR_OFPBAC_BAD_OUT_PORT;
         }
@@ -1127,15 +1244,17 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports,
         return nxm_reg_move_check(ofpact_get_REG_MOVE(a), flow);
 
     case OFPACT_REG_LOAD:
-        if (*dl_type != flow->dl_type) {
-            struct flow updated_flow = *flow;
-            updated_flow.dl_type = *dl_type;
-            return nxm_reg_load_check(ofpact_get_REG_LOAD(a), &updated_flow);
-        } else {
-            return nxm_reg_load_check(ofpact_get_REG_LOAD(a), flow);
-        }
+        return nxm_reg_load_check(ofpact_get_REG_LOAD(a), flow);
+
+    case OFPACT_STACK_PUSH:
+        return nxm_stack_push_check(ofpact_get_STACK_PUSH(a), flow);
+
+    case OFPACT_STACK_POP:
+        return nxm_stack_pop_check(ofpact_get_STACK_POP(a), flow);
 
     case OFPACT_DEC_TTL:
+    case OFPACT_SET_MPLS_TTL:
+    case OFPACT_DEC_MPLS_TTL:
     case OFPACT_SET_TUNNEL:
     case OFPACT_SET_QUEUE:
     case OFPACT_POP_QUEUE:
@@ -1154,16 +1273,32 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports,
         return 0;
 
     case OFPACT_PUSH_MPLS:
-        *dl_type = ofpact_get_PUSH_MPLS(a)->ethertype;
+        flow->dl_type = ofpact_get_PUSH_MPLS(a)->ethertype;
         return 0;
 
     case OFPACT_POP_MPLS:
-        *dl_type = ofpact_get_POP_MPLS(a)->ethertype;
+        flow->dl_type = ofpact_get_POP_MPLS(a)->ethertype;
+        return 0;
+
+    case OFPACT_SAMPLE:
         return 0;
 
     case OFPACT_CLEAR_ACTIONS:
     case OFPACT_WRITE_METADATA:
+        return 0;
+
+    case OFPACT_METER: {
+        uint32_t mid = ofpact_get_METER(a)->meter_id;
+        if (mid == 0 || mid > OFPM13_MAX) {
+            return OFPERR_OFPMMFC_INVALID_METER;
+        }
+        return 0;
+    }
+
     case OFPACT_GOTO_TABLE:
+        if (ofpact_get_GOTO_TABLE(a)->table_id <= table_id) {
+            return OFPERR_OFPBRC_BAD_TABLE_ID;
+        }
         return 0;
 
     default:
@@ -1173,22 +1308,25 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports,
 
 /* Checks that the 'ofpacts_len' bytes of actions in 'ofpacts' are
  * appropriate for a packet with the prerequisites satisfied by 'flow' in a
- * switch with no more than 'max_ports' ports. */
+ * switch with no more than 'max_ports' ports.
+ *
+ * May temporarily modify 'flow', but restores the changes before returning. */
 enum ofperr
 ofpacts_check(const struct ofpact ofpacts[], size_t ofpacts_len,
-              const struct flow *flow, int max_ports)
+              struct flow *flow, ofp_port_t max_ports, uint8_t table_id)
 {
     const struct ofpact *a;
     ovs_be16 dl_type = flow->dl_type;
+    enum ofperr error = 0;
 
     OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
-        enum ofperr error = ofpact_check__(a, flow, max_ports, &dl_type);
+        error = ofpact_check__(a, flow, max_ports, table_id);
         if (error) {
-            return error;
+            break;
         }
     }
-
-    return 0;
+    flow->dl_type = dl_type; /* Restore. */
+    return error;
 }
 
 /* Verifies that the 'ofpacts_len' bytes of actions in 'ofpacts' are
@@ -1203,19 +1341,10 @@ ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len)
     OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
         enum ovs_instruction_type next;
 
-        if (a->type == OFPACT_CLEAR_ACTIONS) {
-            next = OVSINST_OFPIT11_CLEAR_ACTIONS;
-        } else if (a->type == OFPACT_WRITE_METADATA) {
-            next = OVSINST_OFPIT11_WRITE_METADATA;
-        } else if (a->type == OFPACT_GOTO_TABLE) {
-            next = OVSINST_OFPIT11_GOTO_TABLE;
-        } else {
-            next = OVSINST_OFPIT11_APPLY_ACTIONS;
-        }
-
+        next = ovs_instruction_type_from_ofpact_type(a->type);
         if (inst != OVSINST_OFPIT11_APPLY_ACTIONS && next <= inst) {
-            const char *name = ofpact_instruction_name_from_type(inst);
-            const char *next_name = ofpact_instruction_name_from_type(next);
+            const char *name = ovs_instruction_name_from_type(inst);
+            const char *next_name = ovs_instruction_name_from_type(next);
 
             if (next == inst) {
                 VLOG_WARN("duplicate %s instruction not allowed, for OpenFlow "
@@ -1261,7 +1390,7 @@ ofpact_resubmit_to_nxast(const struct ofpact_resubmit *resubmit,
         nar = ofputil_put_NXAST_RESUBMIT_TABLE(out);
         nar->table = resubmit->table_id;
     }
-    nar->in_port = htons(resubmit->in_port);
+    nar->in_port = htons(ofp_to_u16(resubmit->in_port));
 }
 
 static void
@@ -1355,6 +1484,19 @@ ofpact_fin_timeout_to_nxast(const struct ofpact_fin_timeout *fin_timeout,
     naft->fin_hard_timeout = htons(fin_timeout->fin_hard_timeout);
 }
 
+static void
+ofpact_sample_to_nxast(const struct ofpact_sample *os,
+                       struct ofpbuf *out)
+{
+    struct nx_action_sample *nas;
+
+    nas = ofputil_put_NXAST_SAMPLE(out);
+    nas->probability = htons(os->probability);
+    nas->collector_set_id = htonl(os->collector_set_id);
+    nas->obs_domain_id = htonl(os->obs_domain_id);
+    nas->obs_point_id = htonl(os->obs_point_id);
+}
+
 static void
 ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
 {
@@ -1379,10 +1521,27 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
         nxm_reg_load_to_nxast(ofpact_get_REG_LOAD(a), out);
         break;
 
+    case OFPACT_STACK_PUSH:
+        nxm_stack_push_to_nxast(ofpact_get_STACK_PUSH(a), out);
+        break;
+
+    case OFPACT_STACK_POP:
+        nxm_stack_pop_to_nxast(ofpact_get_STACK_POP(a), out);
+        break;
+
     case OFPACT_DEC_TTL:
         ofpact_dec_ttl_to_nxast(ofpact_get_DEC_TTL(a), out);
         break;
 
+    case OFPACT_SET_MPLS_TTL:
+        ofputil_put_NXAST_SET_MPLS_TTL(out)->ttl
+            = ofpact_get_SET_MPLS_TTL(a)->ttl;
+        break;
+
+    case OFPACT_DEC_MPLS_TTL:
+        ofputil_put_NXAST_DEC_MPLS_TTL(out);
+        break;
+
     case OFPACT_SET_TUNNEL:
         ofpact_set_tunnel_to_nxast(ofpact_get_SET_TUNNEL(a), out);
         break;
@@ -1434,6 +1593,10 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
             ofpact_get_POP_MPLS(a)->ethertype;
         break;
 
+    case OFPACT_SAMPLE:
+        ofpact_sample_to_nxast(ofpact_get_SAMPLE(a), out);
+        break;
+
     case OFPACT_OUTPUT:
     case OFPACT_ENQUEUE:
     case OFPACT_SET_VLAN_VID:
@@ -1449,6 +1612,7 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_SET_L4_DST_PORT:
     case OFPACT_CLEAR_ACTIONS:
     case OFPACT_GOTO_TABLE:
+    case OFPACT_METER:
         NOT_REACHED();
     }
 }
@@ -1462,7 +1626,7 @@ ofpact_output_to_openflow10(const struct ofpact_output *output,
     struct ofp10_action_output *oao;
 
     oao = ofputil_put_OFPAT10_OUTPUT(out);
-    oao->port = htons(output->port);
+    oao->port = htons(ofp_to_u16(output->port));
     oao->max_len = htons(output->max_len);
 }
 
@@ -1473,7 +1637,7 @@ ofpact_enqueue_to_openflow10(const struct ofpact_enqueue *enqueue,
     struct ofp10_action_enqueue *oae;
 
     oae = ofputil_put_OFPAT10_ENQUEUE(out);
-    oae->port = htons(enqueue->port);
+    oae->port = htons(ofp_to_u16(enqueue->port));
     oae->queue_id = htonl(enqueue->queue);
 }
 
@@ -1541,6 +1705,7 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_PUSH_VLAN:
     case OFPACT_CLEAR_ACTIONS:
     case OFPACT_GOTO_TABLE:
+    case OFPACT_METER:
         /* XXX */
         break;
 
@@ -1549,7 +1714,11 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_BUNDLE:
     case OFPACT_REG_MOVE:
     case OFPACT_REG_LOAD:
+    case OFPACT_STACK_PUSH:
+    case OFPACT_STACK_POP:
     case OFPACT_DEC_TTL:
+    case OFPACT_SET_MPLS_TTL:
+    case OFPACT_DEC_MPLS_TTL:
     case OFPACT_SET_TUNNEL:
     case OFPACT_WRITE_METADATA:
     case OFPACT_SET_QUEUE:
@@ -1562,6 +1731,7 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_EXIT:
     case OFPACT_PUSH_MPLS:
     case OFPACT_POP_MPLS:
+    case OFPACT_SAMPLE:
         ofpact_to_nxast(a, out);
         break;
     }
@@ -1682,6 +1852,15 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
         ofpact_dec_ttl_to_openflow11(ofpact_get_DEC_TTL(a), out);
         break;
 
+    case OFPACT_SET_MPLS_TTL:
+        ofputil_put_OFPAT11_SET_MPLS_TTL(out)->mpls_ttl
+            = ofpact_get_SET_MPLS_TTL(a)->ttl;
+        break;
+
+    case OFPACT_DEC_MPLS_TTL:
+        ofputil_put_OFPAT11_DEC_MPLS_TTL(out);
+        break;
+
     case OFPACT_WRITE_METADATA:
         /* OpenFlow 1.1 uses OFPIT_WRITE_METADATA to express this action. */
         break;
@@ -1699,6 +1878,7 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
 
     case OFPACT_CLEAR_ACTIONS:
     case OFPACT_GOTO_TABLE:
+    case OFPACT_METER:
         NOT_REACHED();
 
     case OFPACT_CONTROLLER:
@@ -1706,6 +1886,8 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_BUNDLE:
     case OFPACT_REG_MOVE:
     case OFPACT_REG_LOAD:
+    case OFPACT_STACK_PUSH:
+    case OFPACT_STACK_POP:
     case OFPACT_SET_TUNNEL:
     case OFPACT_POP_QUEUE:
     case OFPACT_FIN_TIMEOUT:
@@ -1714,6 +1896,7 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_MULTIPATH:
     case OFPACT_NOTE:
     case OFPACT_EXIT:
+    case OFPACT_SAMPLE:
         ofpact_to_nxast(a, out);
         break;
     }
@@ -1758,17 +1941,20 @@ ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
     const struct ofpact *a;
 
     OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
-        /* XXX Write-Actions */
-
-        if (a->type == OFPACT_CLEAR_ACTIONS) {
+        switch (ovs_instruction_type_from_ofpact_type(a->type)) {
+        case OVSINST_OFPIT11_CLEAR_ACTIONS:
             instruction_put_OFPIT11_CLEAR_ACTIONS(openflow);
-        } else if (a->type == OFPACT_GOTO_TABLE) {
-            struct ofp11_instruction_goto_table *oigt;
+            break;
 
+        case OVSINST_OFPIT11_GOTO_TABLE: {
+            struct ofp11_instruction_goto_table *oigt;
             oigt = instruction_put_OFPIT11_GOTO_TABLE(openflow);
             oigt->table_id = ofpact_get_GOTO_TABLE(a)->table_id;
             memset(oigt->pad, 0, sizeof oigt->pad);
-        } else if (a->type == OFPACT_WRITE_METADATA) {
+            break;
+        }
+
+        case OVSINST_OFPIT11_WRITE_METADATA: {
             const struct ofpact_metadata *om;
             struct ofp11_instruction_write_metadata *oiwm;
 
@@ -1776,8 +1962,20 @@ ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
             oiwm = instruction_put_OFPIT11_WRITE_METADATA(openflow);
             oiwm->metadata = om->metadata;
             oiwm->metadata_mask = om->mask;
-        } else if (!ofpact_is_instruction(a)) {
-            /* Apply-actions */
+            break;
+        }
+
+        case OVSINST_OFPIT13_METER: {
+            const struct ofpact_meter *om;
+            struct ofp13_instruction_meter *oim;
+
+            om = ofpact_get_METER(a);
+            oim = instruction_put_OFPIT13_METER(openflow);
+            oim->meter_id = htonl(om->meter_id);
+            break;
+        }
+
+        case OVSINST_OFPIT11_APPLY_ACTIONS: {
             const size_t ofs = openflow->size;
             const size_t ofpacts_len_left =
                 (uint8_t*)ofpact_end(ofpacts, ofpacts_len) - (uint8_t*)a;
@@ -1786,7 +1984,8 @@ ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
 
             instruction_put_OFPIT11_APPLY_ACTIONS(openflow);
             OFPACT_FOR_EACH(action, a, ofpacts_len_left) {
-                if (ofpact_is_instruction(action)) {
+                if (ovs_instruction_type_from_ofpact_type(action->type)
+                    != OVSINST_OFPIT11_APPLY_ACTIONS) {
                     break;
                 }
                 ofpact_to_openflow11(action, openflow);
@@ -1794,13 +1993,18 @@ ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
             }
             ofpacts_update_instruction_actions(openflow, ofs);
             a = processed;
+            break;
+        }
+
+        case OVSINST_OFPIT11_WRITE_ACTIONS:
+            NOT_REACHED();
         }
     }
 }
 \f
 /* Returns true if 'action' outputs to 'port', false otherwise. */
 static bool
-ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
+ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port)
 {
     switch (ofpact->type) {
     case OFPACT_OUTPUT:
@@ -1825,7 +2029,11 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
     case OFPACT_SET_L4_DST_PORT:
     case OFPACT_REG_MOVE:
     case OFPACT_REG_LOAD:
+    case OFPACT_STACK_PUSH:
+    case OFPACT_STACK_POP:
     case OFPACT_DEC_TTL:
+    case OFPACT_SET_MPLS_TTL:
+    case OFPACT_DEC_MPLS_TTL:
     case OFPACT_SET_TUNNEL:
     case OFPACT_WRITE_METADATA:
     case OFPACT_SET_QUEUE:
@@ -1838,8 +2046,10 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
     case OFPACT_EXIT:
     case OFPACT_PUSH_MPLS:
     case OFPACT_POP_MPLS:
+    case OFPACT_SAMPLE:
     case OFPACT_CLEAR_ACTIONS:
     case OFPACT_GOTO_TABLE:
+    case OFPACT_METER:
     default:
         return false;
     }
@@ -1849,7 +2059,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
  * to 'port', false otherwise. */
 bool
 ofpacts_output_to_port(const struct ofpact *ofpacts, size_t ofpacts_len,
-                       uint16_t port)
+                       ofp_port_t port)
 {
     const struct ofpact *a;
 
@@ -1929,12 +2139,13 @@ ofpact_format(const struct ofpact *a, struct ds *s)
     const struct ofpact_controller *controller;
     const struct ofpact_metadata *metadata;
     const struct ofpact_tunnel *tunnel;
-    uint16_t port;
+    const struct ofpact_sample *sample;
+    ofp_port_t port;
 
     switch (a->type) {
     case OFPACT_OUTPUT:
         port = ofpact_get_OUTPUT(a)->port;
-        if (port < OFPP_MAX) {
+        if (ofp_to_u16(port) < ofp_to_u16(OFPP_MAX)) {
             ds_put_format(s, "output:%"PRIu16, port);
         } else {
             ofputil_format_port(port, s);
@@ -1955,8 +2166,11 @@ ofpact_format(const struct ofpact *a, struct ds *s)
 
             ds_put_cstr(s, "controller(");
             if (reason != OFPR_ACTION) {
+                char reasonbuf[OFPUTIL_PACKET_IN_REASON_BUFSIZE];
+
                 ds_put_format(s, "reason=%s,",
-                              ofputil_packet_in_reason_to_string(reason));
+                              ofputil_packet_in_reason_to_string(
+                                  reason, reasonbuf, sizeof reasonbuf));
             }
             if (controller->max_len != UINT16_MAX) {
                 ds_put_format(s, "max_len=%"PRIu16",", controller->max_len);
@@ -2044,10 +2258,27 @@ ofpact_format(const struct ofpact *a, struct ds *s)
         nxm_format_reg_load(ofpact_get_REG_LOAD(a), s);
         break;
 
+    case OFPACT_STACK_PUSH:
+        nxm_format_stack_push(ofpact_get_STACK_PUSH(a), s);
+        break;
+
+    case OFPACT_STACK_POP:
+        nxm_format_stack_pop(ofpact_get_STACK_POP(a), s);
+        break;
+
     case OFPACT_DEC_TTL:
         print_dec_ttl(ofpact_get_DEC_TTL(a), s);
         break;
 
+    case OFPACT_SET_MPLS_TTL:
+        ds_put_format(s, "set_mpls_ttl(%"PRIu8")",
+                      ofpact_get_SET_MPLS_TTL(a)->ttl);
+        break;
+
+    case OFPACT_DEC_MPLS_TTL:
+        ds_put_cstr(s, "dec_mpls_ttl");
+        break;
+
     case OFPACT_SET_TUNNEL:
         tunnel = ofpact_get_SET_TUNNEL(a);
         ds_put_format(s, "set_tunnel%s:%#"PRIx64,
@@ -2113,16 +2344,25 @@ ofpact_format(const struct ofpact *a, struct ds *s)
         ds_put_cstr(s, "exit");
         break;
 
+    case OFPACT_SAMPLE:
+        sample = ofpact_get_SAMPLE(a);
+        ds_put_format(
+            s, "sample(probability=%"PRIu16",collector_set_id=%"PRIu32
+            ",obs_domain_id=%"PRIu32",obs_point_id=%"PRIu32")",
+            sample->probability, sample->collector_set_id,
+            sample->obs_domain_id, sample->obs_point_id);
+        break;
+
     case OFPACT_CLEAR_ACTIONS:
         ds_put_format(s, "%s",
-                      ofpact_instruction_name_from_type(
+                      ovs_instruction_name_from_type(
                           OVSINST_OFPIT11_CLEAR_ACTIONS));
         break;
 
     case OFPACT_WRITE_METADATA:
         metadata = ofpact_get_WRITE_METADATA(a);
         ds_put_format(s, "%s:%#"PRIx64,
-                      ofpact_instruction_name_from_type(
+                      ovs_instruction_name_from_type(
                           OVSINST_OFPIT11_WRITE_METADATA),
                       ntohll(metadata->metadata));
         if (metadata->mask != htonll(UINT64_MAX)) {
@@ -2132,10 +2372,16 @@ ofpact_format(const struct ofpact *a, struct ds *s)
 
     case OFPACT_GOTO_TABLE:
         ds_put_format(s, "%s:%"PRIu8,
-                      ofpact_instruction_name_from_type(
+                      ovs_instruction_name_from_type(
                           OVSINST_OFPIT11_GOTO_TABLE),
                       ofpact_get_GOTO_TABLE(a)->table_id);
         break;
+
+    case OFPACT_METER:
+        ds_put_format(s, "%s:%"PRIu32,
+                      ovs_instruction_name_from_type(OVSINST_OFPIT13_METER),
+                      ofpact_get_METER(a)->meter_id);
+        break;
     }
 }