nicira-ext: Add Nicira actions NXAST_STACK_PUSH and NXAST_STACK_POP.
[sliver-openvswitch.git] / lib / ofp-actions.c
index bb45edc..d405d2d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,7 +16,6 @@
 
 #include <config.h>
 #include "ofp-actions.h"
-#include "autopath.h"
 #include "bundle.h"
 #include "byte-order.h"
 #include "compiler.h"
@@ -27,6 +26,7 @@
 #include "nx-match.h"
 #include "ofp-util.h"
 #include "ofpbuf.h"
+#include "util.h"
 #include "vlog.h"
 
 VLOG_DEFINE_THIS_MODULE(ofp_actions);
@@ -49,7 +49,7 @@ output_from_openflow10(const struct ofp10_action_output *oao,
 }
 
 static enum ofperr
-enqueue_from_openflow10(const struct ofp_action_enqueue *oae,
+enqueue_from_openflow10(const struct ofp10_action_enqueue *oae,
                         struct ofpbuf *out)
 {
     struct ofpact_enqueue *enqueue;
@@ -135,6 +135,23 @@ controller_from_openflow(const struct nx_action_controller *nac,
     oc->reason = nac->reason;
 }
 
+static enum ofperr
+metadata_from_nxast(const struct nx_action_write_metadata *nawm,
+                    struct ofpbuf *out)
+{
+    struct ofpact_metadata *om;
+
+    if (!is_all_zeros(nawm->zeros, sizeof nawm->zeros)) {
+        return OFPERR_NXBRC_MUST_BE_ZERO;
+    }
+
+    om = ofpact_put_WRITE_METADATA(out);
+    om->metadata = nawm->metadata;
+    om->mask = nawm->mask;
+
+    return 0;
+}
+
 static void
 note_from_openflow(const struct nx_action_note *nan, struct ofpbuf *out)
 {
@@ -149,14 +166,14 @@ note_from_openflow(const struct nx_action_note *nan, struct ofpbuf *out)
 }
 
 static enum ofperr
-dec_ttl_from_openflow(struct ofpbuf *out)
+dec_ttl_from_openflow(struct ofpbuf *out, enum ofputil_action_code compat)
 {
     uint16_t id = 0;
     struct ofpact_cnt_ids *ids;
     enum ofperr error = 0;
 
     ids = ofpact_put_DEC_TTL(out);
-    ids->ofpact.compat = OFPUTIL_NXAST_DEC_TTL;
+    ids->ofpact.compat = compat;
     ids->n_controllers = 1;
     ofpbuf_put(out, &id, sizeof id);
     ids = out->l2;
@@ -276,13 +293,14 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
     const struct nx_action_set_queue *nasq;
     const struct nx_action_note *nan;
     const struct nx_action_set_tunnel64 *nast64;
+    const struct nx_action_write_metadata *nawm;
     struct ofpact_tunnel *tunnel;
     enum ofperr error = 0;
 
     switch (code) {
     case OFPUTIL_ACTION_INVALID:
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
-#define OFPAT11_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
         NOT_REACHED();
 
@@ -297,6 +315,11 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
         tunnel->tun_id = ntohl(nast->tun_id);
         break;
 
+    case OFPUTIL_NXAST_WRITE_METADATA:
+        nawm = (const struct nx_action_write_metadata *) a;
+        error = metadata_from_nxast(nawm, out);
+        break;
+
     case OFPUTIL_NXAST_SET_QUEUE:
         nasq = (const struct nx_action_set_queue *) a;
         ofpact_put_SET_QUEUE(out)->queue_id = ntohl(nasq->queue_id);
@@ -316,6 +339,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);
@@ -333,11 +366,6 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
                                         ofpact_put_MULTIPATH(out));
         break;
 
-    case OFPUTIL_NXAST_AUTOPATH__DEPRECATED:
-        error = autopath_from_openflow((const struct nx_action_autopath *) a,
-                                       ofpact_put_AUTOPATH(out));
-        break;
-
     case OFPUTIL_NXAST_BUNDLE:
     case OFPUTIL_NXAST_BUNDLE_LOAD:
         error = bundle_from_openflow((const struct nx_action_bundle *) a, out);
@@ -362,7 +390,7 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
         break;
 
     case OFPUTIL_NXAST_DEC_TTL:
-        error = dec_ttl_from_openflow(out);
+        error = dec_ttl_from_openflow(out, code);
         break;
 
     case OFPUTIL_NXAST_DEC_TTL_CNT_IDS:
@@ -378,6 +406,34 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
     case OFPUTIL_NXAST_CONTROLLER:
         controller_from_openflow((const struct nx_action_controller *) a, out);
         break;
+
+    case OFPUTIL_NXAST_PUSH_MPLS: {
+        struct nx_action_push_mpls *nxapm = (struct nx_action_push_mpls *)a;
+        if (!eth_type_mpls(nxapm->ethertype)) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_PUSH_MPLS(out)->ethertype = nxapm->ethertype;
+        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)) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_POP_MPLS(out)->ethertype = nxapm->ethertype;
+        break;
+    }
     }
 
     return error;
@@ -396,7 +452,7 @@ ofpact_from_openflow10(const union ofp_action *a, struct ofpbuf *out)
 
     switch (code) {
     case OFPUTIL_ACTION_INVALID:
-#define OFPAT11_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
         NOT_REACHED();
 
@@ -456,7 +512,7 @@ ofpact_from_openflow10(const union ofp_action *a, struct ofpbuf *out)
         break;
 
     case OFPUTIL_OFPAT10_ENQUEUE:
-        error = enqueue_from_openflow10((const struct ofp_action_enqueue *) a,
+        error = enqueue_from_openflow10((const struct ofp10_action_enqueue *) a,
                                         out);
         break;
 
@@ -567,6 +623,12 @@ ofpacts_pull_actions(struct ofpbuf *openflow, unsigned int actions_len,
     }
 
     error = translate(actions, actions_len / OFP_ACTION_ALIGN, ofpacts);
+    if (error) {
+        ofpbuf_clear(ofpacts);
+        return error;
+    }
+
+    error = ofpacts_verify(ofpacts->data, ofpacts->size);
     if (error) {
         ofpbuf_clear(ofpacts);
     }
@@ -607,19 +669,24 @@ static enum ofperr
 decode_openflow11_action(const union ofp_action *a,
                          enum ofputil_action_code *code)
 {
+    uint16_t len;
+
     switch (a->type) {
     case CONSTANT_HTONS(OFPAT11_EXPERIMENTER):
         return decode_nxast_action(a, code);
 
-#define OFPAT11_ACTION(ENUM, STRUCT, NAME)                          \
-        case CONSTANT_HTONS(ENUM):                                  \
-            if (a->header.len == htons(sizeof(struct STRUCT))) {    \
-                *code = OFPUTIL_##ENUM;                             \
-                return 0;                                           \
-            } else {                                                \
-                return OFPERR_OFPBAC_BAD_LEN;                       \
-            }                                                       \
-            break;
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)  \
+        case CONSTANT_HTONS(ENUM):                      \
+            len = ntohs(a->header.len);                 \
+            if (EXTENSIBLE                              \
+                ? len >= sizeof(struct STRUCT)          \
+                : len == sizeof(struct STRUCT)) {       \
+                *code = OFPUTIL_##ENUM;                 \
+                return 0;                               \
+            } else {                                    \
+                return OFPERR_OFPBAC_BAD_LEN;           \
+            }                                           \
+            NOT_REACHED();
 #include "ofp-util.def"
 
     default:
@@ -680,6 +747,24 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
         ofpact_put_SET_VLAN_PCP(out)->vlan_pcp = a->vlan_pcp.vlan_pcp;
         break;
 
+    case OFPUTIL_OFPAT11_PUSH_VLAN:
+        if (((const struct ofp11_action_push *)a)->ethertype !=
+            htons(ETH_TYPE_VLAN_8021Q)) {
+            /* XXX 802.1AD(QinQ) isn't supported at the moment */
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_PUSH_VLAN(out);
+        break;
+
+    case OFPUTIL_OFPAT11_POP_VLAN:
+        ofpact_put_STRIP_VLAN(out);
+        break;
+
+    case OFPUTIL_OFPAT11_SET_QUEUE:
+        ofpact_put_SET_QUEUE(out)->queue_id =
+            ntohl(((const struct ofp11_action_set_queue *)a)->queue_id);
+        break;
+
     case OFPUTIL_OFPAT11_SET_DL_SRC:
         memcpy(ofpact_put_SET_ETH_SRC(out)->mac,
                ((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
@@ -690,6 +775,10 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
                ((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
         break;
 
+    case OFPUTIL_OFPAT11_DEC_NW_TTL:
+        dec_ttl_from_openflow(out, code);
+        break;
+
     case OFPUTIL_OFPAT11_SET_NW_SRC:
         ofpact_put_SET_IPV4_SRC(out)->ipv4 = a->nw_addr.nw_addr;
         break;
@@ -714,8 +803,36 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
         break;
 
     case OFPUTIL_OFPAT12_SET_FIELD:
-        /* Not yet implemented. */
+        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)) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_PUSH_MPLS(out)->ethertype = oap->ethertype;
+        break;
+    }
+
+    case OFPUTIL_OFPAT11_POP_MPLS: {
+        struct ofp11_action_pop_mpls *oapm = (struct ofp11_action_pop_mpls *)a;
+        if (eth_type_mpls(oapm->ethertype)) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_POP_MPLS(out)->ethertype = oapm->ethertype;
         break;
+    }
 
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
@@ -738,7 +855,7 @@ ofpacts_from_openflow11(const union ofp_action *in, size_t n_in,
     static inline const struct STRUCT *                         \
     instruction_get_##ENUM(const struct ofp11_instruction *inst)\
     {                                                           \
-        assert(inst->type == htons(ENUM));                      \
+        ovs_assert(inst->type == htons(ENUM));                  \
         return (struct STRUCT *)inst;                           \
     }                                                           \
                                                                 \
@@ -861,7 +978,9 @@ decode_openflow11_instructions(const struct ofp11_instruction insts[],
         }
 
         if (out[type]) {
-            return OFPERR_OFPIT_BAD_INSTRUCTION;
+            return OFPERR_OFPBAC_UNSUPPORTED_ORDER; /* No specific code for
+                                                     * a duplicate instruction
+                                                     * exist */
         }
         out[type] = inst;
     }
@@ -953,15 +1072,39 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
             goto exit;
         }
     }
+    if (insts[OVSINST_OFPIT11_CLEAR_ACTIONS]) {
+        instruction_get_OFPIT11_CLEAR_ACTIONS(
+            insts[OVSINST_OFPIT11_CLEAR_ACTIONS]);
+        ofpact_put_CLEAR_ACTIONS(ofpacts);
+    }
+    /* XXX Write-Actions */
+    if (insts[OVSINST_OFPIT11_WRITE_METADATA]) {
+        const struct ofp11_instruction_write_metadata *oiwm;
+        struct ofpact_metadata *om;
 
-    if (insts[OVSINST_OFPIT11_GOTO_TABLE] ||
-        insts[OVSINST_OFPIT11_WRITE_METADATA] ||
-        insts[OVSINST_OFPIT11_WRITE_ACTIONS] ||
-        insts[OVSINST_OFPIT11_CLEAR_ACTIONS]) {
+        oiwm = (const struct ofp11_instruction_write_metadata *)
+            insts[OVSINST_OFPIT11_WRITE_METADATA];
+
+        om = ofpact_put_WRITE_METADATA(ofpacts);
+        om->metadata = oiwm->metadata;
+        om->mask = oiwm->metadata_mask;
+    }
+    if (insts[OVSINST_OFPIT11_GOTO_TABLE]) {
+        const struct ofp11_instruction_goto_table *oigt;
+        struct ofpact_goto_table *ogt;
+
+        oigt = instruction_get_OFPIT11_GOTO_TABLE(
+            insts[OVSINST_OFPIT11_GOTO_TABLE]);
+        ogt = ofpact_put_GOTO_TABLE(ofpacts);
+        ogt->table_id = oigt->table_id;
+    }
+
+    if (insts[OVSINST_OFPIT11_WRITE_ACTIONS]) {
         error = OFPERR_OFPBIC_UNSUP_INST;
         goto exit;
     }
 
+    error = ofpacts_verify(ofpacts->data, ofpacts->size);
 exit:
     if (error) {
         ofpbuf_clear(ofpacts);
@@ -970,7 +1113,8 @@ exit:
 }
 \f
 static enum ofperr
-ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
+ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports,
+               ovs_be16 *dl_type)
 {
     const struct ofpact_enqueue *enqueue;
 
@@ -999,6 +1143,7 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
     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:
@@ -1012,9 +1157,23 @@ 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:
-        return nxm_reg_load_check(ofpact_get_REG_LOAD(a), flow);
+        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);
+        }
+
+    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:
@@ -1028,13 +1187,23 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
     case OFPACT_MULTIPATH:
         return multipath_check(ofpact_get_MULTIPATH(a), flow);
 
-    case OFPACT_AUTOPATH:
-        return autopath_check(ofpact_get_AUTOPATH(a), flow);
-
     case OFPACT_NOTE:
     case OFPACT_EXIT:
         return 0;
 
+    case OFPACT_PUSH_MPLS:
+        *dl_type = ofpact_get_PUSH_MPLS(a)->ethertype;
+        return 0;
+
+    case OFPACT_POP_MPLS:
+        *dl_type = ofpact_get_POP_MPLS(a)->ethertype;
+        return 0;
+
+    case OFPACT_CLEAR_ACTIONS:
+    case OFPACT_WRITE_METADATA:
+    case OFPACT_GOTO_TABLE:
+        return 0;
+
     default:
         NOT_REACHED();
     }
@@ -1048,9 +1217,10 @@ ofpacts_check(const struct ofpact ofpacts[], size_t ofpacts_len,
               const struct flow *flow, int max_ports)
 {
     const struct ofpact *a;
+    ovs_be16 dl_type = flow->dl_type;
 
     OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
-        enum ofperr error = ofpact_check__(a, flow, max_ports);
+        enum ofperr error = ofpact_check__(a, flow, max_ports, &dl_type);
         if (error) {
             return error;
         }
@@ -1058,6 +1228,49 @@ ofpacts_check(const struct ofpact ofpacts[], size_t ofpacts_len,
 
     return 0;
 }
+
+/* Verifies that the 'ofpacts_len' bytes of actions in 'ofpacts' are
+ * in the appropriate order as defined by the OpenFlow spec. */
+enum ofperr
+ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len)
+{
+    const struct ofpact *a;
+    enum ovs_instruction_type inst;
+
+    inst = OVSINST_OFPIT11_APPLY_ACTIONS;
+    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;
+        }
+
+        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);
+
+            if (next == inst) {
+                VLOG_WARN("duplicate %s instruction not allowed, for OpenFlow "
+                          "1.1+ compatibility", name);
+            } else {
+                VLOG_WARN("invalid instruction ordering: %s must appear "
+                          "before %s, for OpenFlow 1.1+ compatibility",
+                          next_name, name);
+            }
+            return OFPERR_OFPBAC_UNSUPPORTED_ORDER;
+        }
+
+        inst = next;
+    }
+
+    return 0;
+}
 \f
 /* Converting ofpacts to Nicira OpenFlow extensions. */
 
@@ -1103,6 +1316,17 @@ ofpact_set_tunnel_to_nxast(const struct ofpact_tunnel *tunnel,
     }
 }
 
+static void
+ofpact_write_metadata_to_nxast(const struct ofpact_metadata *om,
+                               struct ofpbuf *out)
+{
+    struct nx_action_write_metadata *nawm;
+
+    nawm = ofputil_put_NXAST_WRITE_METADATA(out);
+    nawm->metadata = om->metadata;
+    nawm->mask = om->mask;
+}
+
 static void
 ofpact_note_to_nxast(const struct ofpact_note *note, struct ofpbuf *out)
 {
@@ -1193,14 +1417,35 @@ 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;
 
+    case OFPACT_WRITE_METADATA:
+        ofpact_write_metadata_to_nxast(ofpact_get_WRITE_METADATA(a), out);
+        break;
+
     case OFPACT_SET_QUEUE:
         ofputil_put_NXAST_SET_QUEUE(out)->queue_id
             = htonl(ofpact_get_SET_QUEUE(a)->queue_id);
@@ -1226,10 +1471,6 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
         multipath_to_nxast(ofpact_get_MULTIPATH(a), out);
         break;
 
-    case OFPACT_AUTOPATH:
-        autopath_to_nxast(ofpact_get_AUTOPATH(a), out);
-        break;
-
     case OFPACT_NOTE:
         ofpact_note_to_nxast(ofpact_get_NOTE(a), out);
         break;
@@ -1238,11 +1479,22 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
         ofputil_put_NXAST_EXIT(out);
         break;
 
+    case OFPACT_PUSH_MPLS:
+        ofputil_put_NXAST_PUSH_MPLS(out)->ethertype =
+            ofpact_get_PUSH_MPLS(a)->ethertype;
+        break;
+
+    case OFPACT_POP_MPLS:
+        ofputil_put_NXAST_POP_MPLS(out)->ethertype =
+            ofpact_get_POP_MPLS(a)->ethertype;
+        break;
+
     case OFPACT_OUTPUT:
     case OFPACT_ENQUEUE:
     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:
@@ -1250,6 +1502,8 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_SET_IPV4_DSCP:
     case OFPACT_SET_L4_SRC_PORT:
     case OFPACT_SET_L4_DST_PORT:
+    case OFPACT_CLEAR_ACTIONS:
+    case OFPACT_GOTO_TABLE:
         NOT_REACHED();
     }
 }
@@ -1271,7 +1525,7 @@ static void
 ofpact_enqueue_to_openflow10(const struct ofpact_enqueue *enqueue,
                              struct ofpbuf *out)
 {
-    struct ofp_action_enqueue *oae;
+    struct ofp10_action_enqueue *oae;
 
     oae = ofputil_put_OFPAT10_ENQUEUE(out);
     oae->port = htons(enqueue->port);
@@ -1339,22 +1593,34 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
             = htons(ofpact_get_SET_L4_DST_PORT(a)->port);
         break;
 
+    case OFPACT_PUSH_VLAN:
+    case OFPACT_CLEAR_ACTIONS:
+    case OFPACT_GOTO_TABLE:
+        /* XXX */
+        break;
+
     case OFPACT_CONTROLLER:
     case OFPACT_OUTPUT_REG:
     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:
     case OFPACT_POP_QUEUE:
     case OFPACT_FIN_TIMEOUT:
     case OFPACT_RESUBMIT:
     case OFPACT_LEARN:
     case OFPACT_MULTIPATH:
-    case OFPACT_AUTOPATH:
     case OFPACT_NOTE:
     case OFPACT_EXIT:
+    case OFPACT_PUSH_MPLS:
+    case OFPACT_POP_MPLS:
         ofpact_to_nxast(a, out);
         break;
     }
@@ -1387,6 +1653,19 @@ ofpact_output_to_openflow11(const struct ofpact_output *output,
     oao->max_len = htons(output->max_len);
 }
 
+static void
+ofpact_dec_ttl_to_openflow11(const struct ofpact_cnt_ids *dec_ttl,
+                             struct ofpbuf *out)
+{
+    if (dec_ttl->n_controllers == 1 && dec_ttl->cnt_ids[0] == 0
+        && (!dec_ttl->ofpact.compat ||
+            dec_ttl->ofpact.compat == OFPUTIL_OFPAT11_DEC_NW_TTL)) {
+        ofputil_put_OFPAT11_DEC_NW_TTL(out);
+    } else {
+        ofpact_dec_ttl_to_nxast(dec_ttl, out);
+    }
+}
+
 static void
 ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
 {
@@ -1409,7 +1688,18 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
         break;
 
     case OFPACT_STRIP_VLAN:
-        /* XXX */
+        ofputil_put_OFPAT11_POP_VLAN(out);
+        break;
+
+    case OFPACT_PUSH_VLAN:
+        /* XXX ETH_TYPE_VLAN_8021AD case */
+        ofputil_put_OFPAT11_PUSH_VLAN(out)->ethertype =
+            htons(ETH_TYPE_VLAN_8021Q);
+        break;
+
+    case OFPACT_SET_QUEUE:
+        ofputil_put_OFPAT11_SET_QUEUE(out)->queue_id
+            = htonl(ofpact_get_SET_QUEUE(a)->queue_id);
         break;
 
     case OFPACT_SET_ETH_SRC:
@@ -1447,20 +1737,51 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
             = htons(ofpact_get_SET_L4_DST_PORT(a)->port);
         break;
 
+    case OFPACT_DEC_TTL:
+        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;
+
+    case OFPACT_PUSH_MPLS:
+        ofputil_put_OFPAT11_PUSH_MPLS(out)->ethertype =
+            ofpact_get_PUSH_MPLS(a)->ethertype;
+        break;
+
+    case OFPACT_POP_MPLS:
+        ofputil_put_OFPAT11_POP_MPLS(out)->ethertype =
+            ofpact_get_POP_MPLS(a)->ethertype;
+
+        break;
+
+    case OFPACT_CLEAR_ACTIONS:
+    case OFPACT_GOTO_TABLE:
+        NOT_REACHED();
+
     case OFPACT_CONTROLLER:
     case OFPACT_OUTPUT_REG:
     case OFPACT_BUNDLE:
     case OFPACT_REG_MOVE:
     case OFPACT_REG_LOAD:
-    case OFPACT_DEC_TTL:
+    case OFPACT_STACK_PUSH:
+    case OFPACT_STACK_POP:
     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_AUTOPATH:
     case OFPACT_NOTE:
     case OFPACT_EXIT:
         ofpact_to_nxast(a, out);
@@ -1485,18 +1806,10 @@ ofpacts_put_openflow11_actions(const struct ofpact ofpacts[],
     return openflow->size - start_size;
 }
 
-void
-ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
-                                    size_t ofpacts_len,
-                                    struct ofpbuf *openflow)
+static void
+ofpacts_update_instruction_actions(struct ofpbuf *openflow, size_t ofs)
 {
     struct ofp11_instruction_actions *oia;
-    size_t ofs;
-
-    /* Put an OFPIT11_APPLY_ACTIONS instruction and fill it in. */
-    ofs = openflow->size;
-    instruction_put_OFPIT11_APPLY_ACTIONS(openflow);
-    ofpacts_put_openflow11_actions(ofpacts, ofpacts_len, openflow);
 
     /* Update the instruction's length (or, if it's empty, delete it). */
     oia = ofpbuf_at_assert(openflow, ofs, sizeof *oia);
@@ -1506,6 +1819,54 @@ ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
         openflow->size = ofs;
     }
 }
+
+void
+ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
+                                    size_t ofpacts_len,
+                                    struct ofpbuf *openflow)
+{
+    const struct ofpact *a;
+
+    OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
+        /* XXX Write-Actions */
+
+        if (a->type == OFPACT_CLEAR_ACTIONS) {
+            instruction_put_OFPIT11_CLEAR_ACTIONS(openflow);
+        } else if (a->type == OFPACT_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) {
+            const struct ofpact_metadata *om;
+            struct ofp11_instruction_write_metadata *oiwm;
+
+            om = ofpact_get_WRITE_METADATA(a);
+            oiwm = instruction_put_OFPIT11_WRITE_METADATA(openflow);
+            oiwm->metadata = om->metadata;
+            oiwm->metadata_mask = om->mask;
+        } else if (!ofpact_is_instruction(a)) {
+            /* Apply-actions */
+            const size_t ofs = openflow->size;
+            const size_t ofpacts_len_left =
+                (uint8_t*)ofpact_end(ofpacts, ofpacts_len) - (uint8_t*)a;
+            const struct ofpact *action;
+            const struct ofpact *processed = a;
+
+            instruction_put_OFPIT11_APPLY_ACTIONS(openflow);
+            OFPACT_FOR_EACH(action, a, ofpacts_len_left) {
+                if (ofpact_is_instruction(action)) {
+                    break;
+                }
+                ofpact_to_openflow11(action, openflow);
+                processed = action;
+            }
+            ofpacts_update_instruction_actions(openflow, ofs);
+            a = processed;
+        }
+    }
+}
 \f
 /* Returns true if 'action' outputs to 'port', false otherwise. */
 static bool
@@ -1524,6 +1885,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
     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:
@@ -1533,17 +1895,25 @@ 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:
     case OFPACT_POP_QUEUE:
     case OFPACT_FIN_TIMEOUT:
     case OFPACT_RESUBMIT:
     case OFPACT_LEARN:
     case OFPACT_MULTIPATH:
-    case OFPACT_AUTOPATH:
     case OFPACT_NOTE:
     case OFPACT_EXIT:
+    case OFPACT_PUSH_MPLS:
+    case OFPACT_POP_MPLS:
+    case OFPACT_CLEAR_ACTIONS:
+    case OFPACT_GOTO_TABLE:
     default:
         return false;
     }
@@ -1630,8 +2000,8 @@ ofpact_format(const struct ofpact *a, struct ds *s)
 {
     const struct ofpact_enqueue *enqueue;
     const struct ofpact_resubmit *resubmit;
-    const struct ofpact_autopath *autopath;
     const struct ofpact_controller *controller;
+    const struct ofpact_metadata *metadata;
     const struct ofpact_tunnel *tunnel;
     uint16_t port;
 
@@ -1703,6 +2073,11 @@ ofpact_format(const struct ofpact *a, struct ds *s)
         ds_put_cstr(s, "strip_vlan");
         break;
 
+    case OFPACT_PUSH_VLAN:
+        /* XXX 802.1AD case*/
+        ds_put_format(s, "push_vlan:%#"PRIx16, ETH_TYPE_VLAN_8021Q);
+        break;
+
     case OFPACT_SET_ETH_SRC:
         ds_put_format(s, "mod_dl_src:"ETH_ADDR_FMT,
                       ETH_ADDR_ARGS(ofpact_get_SET_ETH_SRC(a)->mac));
@@ -1715,12 +2090,12 @@ ofpact_format(const struct ofpact *a, struct ds *s)
 
     case OFPACT_SET_IPV4_SRC:
         ds_put_format(s, "mod_nw_src:"IP_FMT,
-                      IP_ARGS(&ofpact_get_SET_IPV4_SRC(a)->ipv4));
+                      IP_ARGS(ofpact_get_SET_IPV4_SRC(a)->ipv4));
         break;
 
     case OFPACT_SET_IPV4_DST:
         ds_put_format(s, "mod_nw_dst:"IP_FMT,
-                      IP_ARGS(&ofpact_get_SET_IPV4_DST(a)->ipv4));
+                      IP_ARGS(ofpact_get_SET_IPV4_DST(a)->ipv4));
         break;
 
     case OFPACT_SET_IPV4_DSCP:
@@ -1743,10 +2118,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,
@@ -1794,22 +2186,47 @@ ofpact_format(const struct ofpact *a, struct ds *s)
         multipath_format(ofpact_get_MULTIPATH(a), s);
         break;
 
-    case OFPACT_AUTOPATH:
-        autopath = ofpact_get_AUTOPATH(a);
-        ds_put_cstr(s, "autopath(");
-        ofputil_format_port(autopath->port, s);
-        ds_put_char(s, ',');
-        mf_format_subfield(&autopath->dst, s);
-        ds_put_char(s, ')');
-        break;
-
     case OFPACT_NOTE:
         print_note(ofpact_get_NOTE(a), s);
         break;
 
+    case OFPACT_PUSH_MPLS:
+        ds_put_format(s, "push_mpls:0x%04"PRIx16,
+                      ntohs(ofpact_get_PUSH_MPLS(a)->ethertype));
+        break;
+
+    case OFPACT_POP_MPLS:
+        ds_put_format(s, "pop_mpls:0x%04"PRIx16,
+                      ntohs(ofpact_get_POP_MPLS(a)->ethertype));
+        break;
+
     case OFPACT_EXIT:
         ds_put_cstr(s, "exit");
         break;
+
+    case OFPACT_CLEAR_ACTIONS:
+        ds_put_format(s, "%s",
+                      ofpact_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(
+                          OVSINST_OFPIT11_WRITE_METADATA),
+                      ntohll(metadata->metadata));
+        if (metadata->mask != htonll(UINT64_MAX)) {
+            ds_put_format(s, "/%#"PRIx64, ntohll(metadata->mask));
+        }
+        break;
+
+    case OFPACT_GOTO_TABLE:
+        ds_put_format(s, "%s:%"PRIu8,
+                      ofpact_instruction_name_from_type(
+                          OVSINST_OFPIT11_GOTO_TABLE),
+                      ofpact_get_GOTO_TABLE(a)->table_id);
+        break;
     }
 }
 
@@ -1829,6 +2246,8 @@ ofpacts_format(const struct ofpact *ofpacts, size_t ofpacts_len,
             if (a != ofpacts) {
                 ds_put_cstr(string, ",");
             }
+
+            /* XXX write-actions */
             ofpact_format(a, string);
         }
     }
@@ -1865,7 +2284,7 @@ ofpact_init(struct ofpact *ofpact, enum ofpact_type type, size_t len)
 void
 ofpact_update_len(struct ofpbuf *ofpacts, struct ofpact *ofpact)
 {
-    assert(ofpact == ofpacts->l2);
+    ovs_assert(ofpact == ofpacts->l2);
     ofpact->len = (char *) ofpbuf_tail(ofpacts) - (char *) ofpact;
 }
 
@@ -1887,3 +2306,15 @@ ofpact_pad(struct ofpbuf *ofpacts)
         ofpbuf_put_zeros(ofpacts, OFPACT_ALIGNTO - rem);
     }
 }
+
+void
+ofpact_set_field_init(struct ofpact_reg_load *load, const struct mf_field *mf,
+                      const void *src)
+{
+    load->ofpact.compat = OFPUTIL_OFPAT12_SET_FIELD;
+    load->dst.field = mf;
+    load->dst.ofs = 0;
+    load->dst.n_bits = mf->n_bits;
+    bitwise_copy(src, mf->n_bytes, load->dst.ofs,
+                 &load->subvalue, sizeof load->subvalue, 0, mf->n_bits);
+}