[ovs-dev] [of1.1 rollup 16/20] ofp-actions: Support decoding OpenFlow 1.1 instructions and actions.

Ben Pfaff blp at nicira.com
Tue Jun 12 07:32:20 UTC 2012


This builds and doesn't break any existing unit tests, but nothing
calls it yet (and it doesn't have any unit tests of its own) so it
can hardly be called useful.

Left to do:

    - Instructions other than Apply-Actions.

    - Actions other than the ones that have identical semantics to
      OpenFlow 1.0 actions.

    - Unit tests.

    - Encoding.
---
 DESIGN                             |   13 +
 build-aux/extract-ofp-errors       |    1 +
 include/openflow/openflow-1.0.h    |   59 +----
 include/openflow/openflow-1.1.h    |   20 ++
 include/openflow/openflow-common.h |   55 ++++-
 lib/ofp-actions.c                  |  563 +++++++++++++++++++++++++++++++-----
 lib/ofp-actions.h                  |    9 +-
 lib/ofp-errors.h                   |    5 +-
 lib/ofp-parse.c                    |   10 +
 lib/ofp-util.c                     |   15 +-
 lib/ofp-util.def                   |   26 ++-
 lib/ofp-util.h                     |    9 +-
 ofproto/connmgr.c                  |    2 +-
 ofproto/in-band.c                  |   12 +-
 14 files changed, 643 insertions(+), 156 deletions(-)

diff --git a/DESIGN b/DESIGN
index 0b7afa1..74afefe 100644
--- a/DESIGN
+++ b/DESIGN
@@ -622,6 +622,19 @@ against desired actions in a bytewise fashion:
 	- Open vSwitch zeros padding bytes in action structures,
           regardless of their values when the flows were added.
 
+	- Open vSwitch "normalizes" the instructions in OpenFlow 1.1
+          (and later) in the following way:
+
+              * OVS sorts the instructions into the following order:
+                Apply-Actions, Clear-Actions, Write-Actions,
+                Write-Metadata, Goto-Table.
+
+	      * OVS drops Apply-Actions instructions that have empty
+                action lists.
+
+              * OVS drops Write-Actions instructions that have empty
+                action sets.
+
 Please report other discrepancies, if you notice any, so that we can
 fix or document them.
 
diff --git a/build-aux/extract-ofp-errors b/build-aux/extract-ofp-errors
index efaf103..1ec5ba4 100755
--- a/build-aux/extract-ofp-errors
+++ b/build-aux/extract-ofp-errors
@@ -234,6 +234,7 @@ def extract_ofp_errors(filenames):
                               "NX1.0+": ("OF1.0", "OF1.1", "OF1.2"),
                               "NX1.0":  ("OF1.0",),
                               "NX1.1":  ("OF1.1",),
+                              "NX1.1+": ("OF1.1",),
                               "NX1.2":  ("OF1.2",)}
                 if targets not in target_map:
                     fatal("%s: unknown error domain" % targets)
diff --git a/include/openflow/openflow-1.0.h b/include/openflow/openflow-1.0.h
index d01a0f9..b07d419 100644
--- a/include/openflow/openflow-1.0.h
+++ b/include/openflow/openflow-1.0.h
@@ -234,72 +234,19 @@ enum ofp10_action_type {
  * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max
  * number of bytes to send.  A 'max_len' of zero means no bytes of the
  * packet should be sent. */
-struct ofp_action_output {
+struct ofp10_action_output {
     ovs_be16 type;                  /* OFPAT10_OUTPUT. */
     ovs_be16 len;                   /* Length is 8. */
     ovs_be16 port;                  /* Output port. */
     ovs_be16 max_len;               /* Max length to send to controller. */
 };
-OFP_ASSERT(sizeof(struct ofp_action_output) == 8);
+OFP_ASSERT(sizeof(struct ofp10_action_output) == 8);
 
 /* The VLAN id is 12 bits, so we can use the entire 16 bits to indicate
  * special conditions.  All ones is used to match that no VLAN id was
  * set. */
 #define OFP_VLAN_NONE      0xffff
 
-/* Action structure for OFPAT10_SET_VLAN_VID. */
-struct ofp_action_vlan_vid {
-    ovs_be16 type;                  /* OFPAT10_SET_VLAN_VID. */
-    ovs_be16 len;                   /* Length is 8. */
-    ovs_be16 vlan_vid;              /* VLAN id. */
-    uint8_t pad[2];
-};
-OFP_ASSERT(sizeof(struct ofp_action_vlan_vid) == 8);
-
-/* Action structure for OFPAT10_SET_VLAN_PCP. */
-struct ofp_action_vlan_pcp {
-    ovs_be16 type;                  /* OFPAT10_SET_VLAN_PCP. */
-    ovs_be16 len;                   /* Length is 8. */
-    uint8_t vlan_pcp;               /* VLAN priority. */
-    uint8_t pad[3];
-};
-OFP_ASSERT(sizeof(struct ofp_action_vlan_pcp) == 8);
-
-/* Action structure for OFPAT10_SET_DL_SRC/DST. */
-struct ofp_action_dl_addr {
-    ovs_be16 type;                  /* OFPAT10_SET_DL_SRC/DST. */
-    ovs_be16 len;                   /* Length is 16. */
-    uint8_t dl_addr[OFP_ETH_ALEN];  /* Ethernet address. */
-    uint8_t pad[6];
-};
-OFP_ASSERT(sizeof(struct ofp_action_dl_addr) == 16);
-
-/* Action structure for OFPAT10_SET_NW_SRC/DST. */
-struct ofp_action_nw_addr {
-    ovs_be16 type;                  /* OFPAT10_SET_TW_SRC/DST. */
-    ovs_be16 len;                   /* Length is 8. */
-    ovs_be32 nw_addr;               /* IP address. */
-};
-OFP_ASSERT(sizeof(struct ofp_action_nw_addr) == 8);
-
-/* Action structure for OFPAT10_SET_NW_TOS. */
-struct ofp_action_nw_tos {
-    ovs_be16 type;                  /* OFPAT10_SET_TW_TOS. */
-    ovs_be16 len;                   /* Length is 8. */
-    uint8_t nw_tos;                 /* DSCP in high 6 bits, rest ignored. */
-    uint8_t pad[3];
-};
-OFP_ASSERT(sizeof(struct ofp_action_nw_tos) == 8);
-
-/* Action structure for OFPAT10_SET_TP_SRC/DST. */
-struct ofp_action_tp_port {
-    ovs_be16 type;                  /* OFPAT10_SET_TP_SRC/DST. */
-    ovs_be16 len;                   /* Length is 8. */
-    ovs_be16 tp_port;               /* TCP/UDP port. */
-    uint8_t pad[2];
-};
-OFP_ASSERT(sizeof(struct ofp_action_tp_port) == 8);
-
 /* Action header for OFPAT10_VENDOR. The rest of the body is vendor-defined. */
 struct ofp_action_vendor_header {
     ovs_be16 type;                  /* OFPAT10_VENDOR. */
@@ -338,7 +285,7 @@ union ofp_action {
     ovs_be16 type;
     struct ofp_action_header header;
     struct ofp_action_vendor_header vendor;
-    struct ofp_action_output output;
+    struct ofp10_action_output output10;
     struct ofp_action_vlan_vid vlan_vid;
     struct ofp_action_vlan_pcp vlan_pcp;
     struct ofp_action_nw_addr nw_addr;
diff --git a/include/openflow/openflow-1.1.h b/include/openflow/openflow-1.1.h
index f23620c..eff424f 100644
--- a/include/openflow/openflow-1.1.h
+++ b/include/openflow/openflow-1.1.h
@@ -307,6 +307,16 @@ enum ofp11_instruction_type {
     OFPIT11_EXPERIMENTER = 0xFFFF  /* Experimenter instruction */
 };
 
+#define OFP11_INSTRUCTION_ALIGN 8
+
+/* Generic ofp_instruction structure. */
+struct ofp11_instruction {
+    ovs_be16 type;              /* Instruction type */
+    ovs_be16 len;               /* Length of this struct in bytes. */
+    uint8_t pad[4];             /* Align to 64-bits */
+};
+OFP_ASSERT(sizeof(struct ofp11_instruction) == 8);
+
 /* Instruction structure for OFPIT_GOTO_TABLE */
 struct ofp11_instruction_goto_table {
     ovs_be16 type;                 /* OFPIT_GOTO_TABLE */
@@ -337,6 +347,16 @@ struct ofp11_instruction_actions {
 };
 OFP_ASSERT(sizeof(struct ofp11_instruction_actions) == 8);
 
+/* Instruction structure for experimental instructions */
+struct ofp11_instruction_experimenter {
+    ovs_be16 type;              /* OFPIT11_EXPERIMENTER */
+    ovs_be16 len;               /* Length of this struct in bytes */
+    ovs_be32 experimenter;      /* Experimenter ID which takes the same form
+                                   as in struct ofp_vendor_header. */
+    /* Experimenter-defined arbitrary additional data. */
+};
+OFP_ASSERT(sizeof(struct ofp11_instruction_experimenter) == 8);
+
 /* Action structure for OFPAT_OUTPUT, which sends packets out 'port'.
    * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max
    * number of bytes to send. A 'max_len' of zero means no bytes of the
diff --git a/include/openflow/openflow-common.h b/include/openflow/openflow-common.h
index 69e7341..fb3dfa1 100644
--- a/include/openflow/openflow-common.h
+++ b/include/openflow/openflow-common.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2011 The Board of Trustees of The Leland Stanford
+/* Copyright (c) 2008, 2011, 2012 The Board of Trustees of The Leland Stanford
  * Junior University
  *
  * We are making the OpenFlow specification and associated documentation
@@ -218,6 +218,59 @@ enum ofp_packet_in_reason {
     OFPR_N_REASONS
 };
 
+/* Action structure for OFPAT10_SET_VLAN_VID and OFPAT11_SET_VLAN_VID. */
+struct ofp_action_vlan_vid {
+    ovs_be16 type;                  /* Type. */
+    ovs_be16 len;                   /* Length is 8. */
+    ovs_be16 vlan_vid;              /* VLAN id. */
+    uint8_t pad[2];
+};
+OFP_ASSERT(sizeof(struct ofp_action_vlan_vid) == 8);
+
+/* Action structure for OFPAT10_SET_VLAN_PCP and OFPAT11_SET_VLAN_PCP. */
+struct ofp_action_vlan_pcp {
+    ovs_be16 type;                  /* Type. */
+    ovs_be16 len;                   /* Length is 8. */
+    uint8_t vlan_pcp;               /* VLAN priority. */
+    uint8_t pad[3];
+};
+OFP_ASSERT(sizeof(struct ofp_action_vlan_pcp) == 8);
+
+/* Action structure for OFPAT10_SET_DL_SRC/DST and OFPAT11_SET_DL_SRC/DST. */
+struct ofp_action_dl_addr {
+    ovs_be16 type;                  /* Type. */
+    ovs_be16 len;                   /* Length is 16. */
+    uint8_t dl_addr[OFP_ETH_ALEN];  /* Ethernet address. */
+    uint8_t pad[6];
+};
+OFP_ASSERT(sizeof(struct ofp_action_dl_addr) == 16);
+
+/* Action structure for OFPAT10_SET_NW_SRC/DST and OFPAT11_SET_NW_SRC/DST. */
+struct ofp_action_nw_addr {
+    ovs_be16 type;                  /* Type. */
+    ovs_be16 len;                   /* Length is 8. */
+    ovs_be32 nw_addr;               /* IP address. */
+};
+OFP_ASSERT(sizeof(struct ofp_action_nw_addr) == 8);
+
+/* Action structure for OFPAT10_SET_NW_TOS and OFPAT11_SET_NW_TOS. */
+struct ofp_action_nw_tos {
+    ovs_be16 type;                  /* Type.. */
+    ovs_be16 len;                   /* Length is 8. */
+    uint8_t nw_tos;                 /* DSCP in high 6 bits, rest ignored. */
+    uint8_t pad[3];
+};
+OFP_ASSERT(sizeof(struct ofp_action_nw_tos) == 8);
+
+/* Action structure for OFPAT10_SET_TP_SRC/DST and OFPAT11_SET_TP_SRC/DST. */
+struct ofp_action_tp_port {
+    ovs_be16 type;                  /* Type. */
+    ovs_be16 len;                   /* Length is 8. */
+    ovs_be16 tp_port;               /* TCP/UDP port. */
+    uint8_t pad[2];
+};
+OFP_ASSERT(sizeof(struct ofp_action_tp_port) == 8);
+
 /* Why was this flow removed? */
 enum ofp_flow_removed_reason {
     OFPRR_IDLE_TIMEOUT,         /* Flow idle time exceeded idle_timeout. */
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index cda05dc..6e73947 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -36,7 +36,7 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 /* Converting OpenFlow 1.0 to ofpacts. */
 
 static enum ofperr
-output_from_openflow10(const struct ofp_action_output *oao,
+output_from_openflow10(const struct ofp10_action_output *oao,
                        struct ofpbuf *out)
 {
     struct ofpact_output *output;
@@ -214,7 +214,8 @@ decode_openflow10_action(const union ofp_action *a,
 }
 
 static enum ofperr
-ofpact_from_openflow10__(const union ofp_action *a, struct ofpbuf *out)
+ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
+                  struct ofpbuf *out)
 {
     const struct nx_action_resubmit *nar;
     const struct nx_action_set_tunnel *nast;
@@ -222,79 +223,15 @@ ofpact_from_openflow10__(const union ofp_action *a, struct ofpbuf *out)
     const struct nx_action_note *nan;
     const struct nx_action_set_tunnel64 *nast64;
     struct ofpact_tunnel *tunnel;
-    enum ofputil_action_code code;
-    enum ofperr error;
-
-    error = decode_openflow10_action(a, &code);
-    if (error) {
-        return error;
-    }
+    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:
+#include "ofp-util.def"
         NOT_REACHED();
 
-    case OFPUTIL_OFPAT10_OUTPUT:
-        return output_from_openflow10((const struct ofp_action_output *) a,
-                                      out);
-
-    case OFPUTIL_OFPAT10_SET_VLAN_VID:
-        if (a->vlan_vid.vlan_vid & ~htons(0xfff)) {
-            return OFPERR_OFPBAC_BAD_ARGUMENT;
-        }
-        ofpact_put_SET_VLAN_VID(out)->vlan_vid = ntohs(a->vlan_vid.vlan_vid);
-        break;
-
-    case OFPUTIL_OFPAT10_SET_VLAN_PCP:
-        if (a->vlan_pcp.vlan_pcp & ~7) {
-            return OFPERR_OFPBAC_BAD_ARGUMENT;
-        }
-        ofpact_put_SET_VLAN_PCP(out)->vlan_pcp = a->vlan_pcp.vlan_pcp;
-        break;
-
-    case OFPUTIL_OFPAT10_STRIP_VLAN:
-        ofpact_put_STRIP_VLAN(out);
-        break;
-
-    case OFPUTIL_OFPAT10_SET_DL_SRC:
-        memcpy(ofpact_put_SET_ETH_SRC(out)->mac,
-               ((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
-        break;
-
-    case OFPUTIL_OFPAT10_SET_DL_DST:
-        memcpy(ofpact_put_SET_ETH_DST(out)->mac,
-               ((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
-        break;
-
-    case OFPUTIL_OFPAT10_SET_NW_SRC:
-        ofpact_put_SET_IPV4_SRC(out)->ipv4 = a->nw_addr.nw_addr;
-        break;
-
-    case OFPUTIL_OFPAT10_SET_NW_DST:
-        ofpact_put_SET_IPV4_DST(out)->ipv4 = a->nw_addr.nw_addr;
-        break;
-
-    case OFPUTIL_OFPAT10_SET_NW_TOS:
-        if (a->nw_tos.nw_tos & ~IP_DSCP_MASK) {
-            return OFPERR_OFPBAC_BAD_ARGUMENT;
-        }
-        ofpact_put_SET_IPV4_DSCP(out)->dscp = a->nw_tos.nw_tos;
-        break;
-
-    case OFPUTIL_OFPAT10_SET_TP_SRC:
-        ofpact_put_SET_L4_SRC_PORT(out)->port = ntohs(a->tp_port.tp_port);
-        break;
-
-    case OFPUTIL_OFPAT10_SET_TP_DST:
-        ofpact_put_SET_L4_DST_PORT(out)->port = ntohs(a->tp_port.tp_port);
-
-        break;
-
-    case OFPUTIL_OFPAT10_ENQUEUE:
-        error = enqueue_from_openflow10((const struct ofp_action_enqueue *) a,
-                                        out);
-        break;
-
     case OFPUTIL_NXAST_RESUBMIT:
         resubmit_from_openflow((const struct nx_action_resubmit *) a, out);
         break;
@@ -387,6 +324,108 @@ ofpact_from_openflow10__(const union ofp_action *a, struct ofpbuf *out)
     return error;
 }
 
+static enum ofperr
+ofpact_from_openflow10(const union ofp_action *a, struct ofpbuf *out)
+{
+    enum ofputil_action_code code;
+    enum ofperr error;
+
+    error = decode_openflow10_action(a, &code);
+    if (error) {
+        return error;
+    }
+
+    switch (code) {
+    case OFPUTIL_ACTION_INVALID:
+#define OFPAT11_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
+#include "ofp-util.def"
+        NOT_REACHED();
+
+    case OFPUTIL_OFPAT10_OUTPUT:
+        return output_from_openflow10(&a->output10, out);
+
+    case OFPUTIL_OFPAT10_SET_VLAN_VID:
+        if (a->vlan_vid.vlan_vid & ~htons(0xfff)) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_SET_VLAN_VID(out)->vlan_vid = ntohs(a->vlan_vid.vlan_vid);
+        break;
+
+    case OFPUTIL_OFPAT10_SET_VLAN_PCP:
+        if (a->vlan_pcp.vlan_pcp & ~7) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_SET_VLAN_PCP(out)->vlan_pcp = a->vlan_pcp.vlan_pcp;
+        break;
+
+    case OFPUTIL_OFPAT10_STRIP_VLAN:
+        ofpact_put_STRIP_VLAN(out);
+        break;
+
+    case OFPUTIL_OFPAT10_SET_DL_SRC:
+        memcpy(ofpact_put_SET_ETH_SRC(out)->mac,
+               ((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
+        break;
+
+    case OFPUTIL_OFPAT10_SET_DL_DST:
+        memcpy(ofpact_put_SET_ETH_DST(out)->mac,
+               ((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
+        break;
+
+    case OFPUTIL_OFPAT10_SET_NW_SRC:
+        ofpact_put_SET_IPV4_SRC(out)->ipv4 = a->nw_addr.nw_addr;
+        break;
+
+    case OFPUTIL_OFPAT10_SET_NW_DST:
+        ofpact_put_SET_IPV4_DST(out)->ipv4 = a->nw_addr.nw_addr;
+        break;
+
+    case OFPUTIL_OFPAT10_SET_NW_TOS:
+        if (a->nw_tos.nw_tos & ~IP_DSCP_MASK) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_SET_IPV4_DSCP(out)->dscp = a->nw_tos.nw_tos;
+        break;
+
+    case OFPUTIL_OFPAT10_SET_TP_SRC:
+        ofpact_put_SET_L4_SRC_PORT(out)->port = ntohs(a->tp_port.tp_port);
+        break;
+
+    case OFPUTIL_OFPAT10_SET_TP_DST:
+        ofpact_put_SET_L4_DST_PORT(out)->port = ntohs(a->tp_port.tp_port);
+
+        break;
+
+    case OFPUTIL_OFPAT10_ENQUEUE:
+        error = enqueue_from_openflow10((const struct ofp_action_enqueue *) a,
+                                        out);
+        break;
+
+    case OFPUTIL_NXAST_RESUBMIT:
+    case OFPUTIL_NXAST_SET_TUNNEL:
+    case OFPUTIL_NXAST_SET_QUEUE:
+    case OFPUTIL_NXAST_POP_QUEUE:
+    case OFPUTIL_NXAST_REG_MOVE:
+    case OFPUTIL_NXAST_REG_LOAD:
+    case OFPUTIL_NXAST_NOTE:
+    case OFPUTIL_NXAST_SET_TUNNEL64:
+    case OFPUTIL_NXAST_MULTIPATH:
+    case OFPUTIL_NXAST_AUTOPATH:
+    case OFPUTIL_NXAST_BUNDLE:
+    case OFPUTIL_NXAST_BUNDLE_LOAD:
+    case OFPUTIL_NXAST_OUTPUT_REG:
+    case OFPUTIL_NXAST_RESUBMIT_TABLE:
+    case OFPUTIL_NXAST_LEARN:
+    case OFPUTIL_NXAST_EXIT:
+    case OFPUTIL_NXAST_DEC_TTL:
+    case OFPUTIL_NXAST_FIN_TIMEOUT:
+    case OFPUTIL_NXAST_CONTROLLER:
+        return ofpact_from_nxast(a, code, out);
+    }
+
+    return error;
+}
+
 static inline union ofp_action *
 action_next(const union ofp_action *a)
 {
@@ -411,14 +450,14 @@ action_is_valid(const union ofp_action *a, size_t n_actions)
           (ITER) = action_next(ITER)))
 
 static enum ofperr
-ofpact_from_openflow10(const union ofp_action *in, size_t n_in,
-                       struct ofpbuf *out)
+ofpacts_from_openflow10(const union ofp_action *in, size_t n_in,
+                        struct ofpbuf *out)
 {
     const union ofp_action *a;
     size_t left;
 
     ACTION_FOR_EACH (a, left, in, n_in) {
-        enum ofperr error = ofpact_from_openflow10__(a, out);
+        enum ofperr error = ofpact_from_openflow10(a, out);
         if (error) {
             VLOG_WARN_RL(&rl, "bad action at offset %td (%s)",
                          (a - in) * sizeof *a, ofperr_get_name(error));
@@ -444,8 +483,8 @@ ofpact_from_openflow10(const union ofp_action *in, size_t n_in,
  * This function does not check that the actions are valid in a given context.
  * The caller should do so, with ofpacts_check(). */
 enum ofperr
-ofpacts_pull_openflow(struct ofpbuf *openflow, unsigned int actions_len,
-                      struct ofpbuf *ofpacts)
+ofpacts_pull_openflow10(struct ofpbuf *openflow, unsigned int actions_len,
+                        struct ofpbuf *ofpacts)
 {
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     const union ofp_action *actions;
@@ -467,8 +506,374 @@ ofpacts_pull_openflow(struct ofpbuf *openflow, unsigned int actions_len,
         return OFPERR_OFPBRC_BAD_LEN;
     }
 
-    error = ofpact_from_openflow10(actions, actions_len / OFP_ACTION_ALIGN,
-                                   ofpacts);
+    error = ofpacts_from_openflow10(actions, actions_len / OFP_ACTION_ALIGN,
+                                    ofpacts);
+    if (error) {
+        ofpbuf_clear(ofpacts);
+    }
+    return 0;
+}
+
+/* OpenFlow 1.1 actions. */
+
+/* Parses 'a' to determine its type.  On success stores the correct type into
+ * '*code' and returns 0.  On failure returns an OFPERR_* error code and
+ * '*code' is indeterminate.
+ *
+ * The caller must have already verified that 'a''s length is potentially
+ * correct (that is, a->header.len is nonzero and a multiple of sizeof(union
+ * ofp_action) and no longer than the amount of space allocated to 'a').
+ *
+ * This function verifies that 'a''s length is correct for the type of action
+ * that it represents. */
+static enum ofperr
+decode_openflow11_action(const union ofp_action *a,
+                         enum ofputil_action_code *code)
+{
+    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;
+#include "ofp-util.def"
+
+    default:
+        return OFPERR_OFPBAC_BAD_TYPE;
+    }
+}
+
+static enum ofperr
+output_from_openflow11(const struct ofp11_action_output *oao,
+                       struct ofpbuf *out)
+{
+    struct ofpact_output *output;
+    enum ofperr error;
+
+    output = ofpact_put_OUTPUT(out);
+    output->max_len = ntohs(oao->max_len);
+
+    error = ofputil_port_from_ofp11(oao->port, &output->port);
+    if (error) {
+        return error;
+    }
+
+    return ofputil_check_output_port(output->port, OFPP_MAX);
+}
+
+static enum ofperr
+ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
+{
+    enum ofputil_action_code code;
+    enum ofperr error;
+
+    error = decode_openflow11_action(a, &code);
+    if (error) {
+        return error;
+    }
+
+    switch (code) {
+    case OFPUTIL_ACTION_INVALID:
+#define OFPAT10_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
+#include "ofp-util.def"
+        NOT_REACHED();
+
+    case OFPUTIL_OFPAT11_OUTPUT:
+        return output_from_openflow11((const struct ofp11_action_output *) a,
+                                      out);
+
+    case OFPUTIL_OFPAT11_SET_VLAN_VID:
+        if (a->vlan_vid.vlan_vid & ~htons(0xfff)) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_SET_VLAN_VID(out)->vlan_vid = ntohs(a->vlan_vid.vlan_vid);
+        break;
+
+    case OFPUTIL_OFPAT11_SET_VLAN_PCP:
+        if (a->vlan_pcp.vlan_pcp & ~7) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_SET_VLAN_PCP(out)->vlan_pcp = a->vlan_pcp.vlan_pcp;
+        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);
+        break;
+
+    case OFPUTIL_OFPAT11_SET_DL_DST:
+        memcpy(ofpact_put_SET_ETH_DST(out)->mac,
+               ((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
+        break;
+
+    case OFPUTIL_OFPAT11_SET_NW_SRC:
+        ofpact_put_SET_IPV4_SRC(out)->ipv4 = a->nw_addr.nw_addr;
+        break;
+
+    case OFPUTIL_OFPAT11_SET_NW_DST:
+        ofpact_put_SET_IPV4_DST(out)->ipv4 = a->nw_addr.nw_addr;
+        break;
+
+    case OFPUTIL_OFPAT11_SET_NW_TOS:
+        if (a->nw_tos.nw_tos & ~IP_DSCP_MASK) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_SET_IPV4_DSCP(out)->dscp = a->nw_tos.nw_tos;
+        break;
+
+    case OFPUTIL_OFPAT11_SET_TP_SRC:
+        ofpact_put_SET_L4_SRC_PORT(out)->port = ntohs(a->tp_port.tp_port);
+        break;
+
+    case OFPUTIL_OFPAT11_SET_TP_DST:
+        ofpact_put_SET_L4_DST_PORT(out)->port = ntohs(a->tp_port.tp_port);
+
+        break;
+
+    case OFPUTIL_NXAST_RESUBMIT:
+    case OFPUTIL_NXAST_SET_TUNNEL:
+    case OFPUTIL_NXAST_SET_QUEUE:
+    case OFPUTIL_NXAST_POP_QUEUE:
+    case OFPUTIL_NXAST_REG_MOVE:
+    case OFPUTIL_NXAST_REG_LOAD:
+    case OFPUTIL_NXAST_NOTE:
+    case OFPUTIL_NXAST_SET_TUNNEL64:
+    case OFPUTIL_NXAST_MULTIPATH:
+    case OFPUTIL_NXAST_AUTOPATH:
+    case OFPUTIL_NXAST_BUNDLE:
+    case OFPUTIL_NXAST_BUNDLE_LOAD:
+    case OFPUTIL_NXAST_OUTPUT_REG:
+    case OFPUTIL_NXAST_RESUBMIT_TABLE:
+    case OFPUTIL_NXAST_LEARN:
+    case OFPUTIL_NXAST_EXIT:
+    case OFPUTIL_NXAST_DEC_TTL:
+    case OFPUTIL_NXAST_FIN_TIMEOUT:
+    case OFPUTIL_NXAST_CONTROLLER:
+        return ofpact_from_nxast(a, code, out);
+    }
+
+    return error;
+}
+
+static enum ofperr
+ofpacts_from_openflow11(const union ofp_action *in, size_t n_in,
+                        struct ofpbuf *out)
+{
+    const union ofp_action *a;
+    size_t left;
+
+    ACTION_FOR_EACH (a, left, in, n_in) {
+        enum ofperr error = ofpact_from_openflow11(a, out);
+        if (error) {
+            VLOG_WARN_RL(&rl, "bad action at offset %td (%s)",
+                         (a - in) * sizeof *a, ofperr_get_name(error));
+            return error;
+        }
+    }
+    if (left) {
+        VLOG_WARN_RL(&rl, "bad action format at offset %zu",
+                     (n_in - left) * sizeof *a);
+        return OFPERR_OFPBAC_BAD_LEN;
+    }
+
+    return 0;
+}
+
+/* OpenFlow 1.1 instructions. */
+
+#define OVS_INSTRUCTIONS                                    \
+    DEFINE_INST(OFPIT11_GOTO_TABLE,                         \
+                ofp11_instruction_goto_table,     false,    \
+                "goto_table")                               \
+                                                            \
+    DEFINE_INST(OFPIT11_WRITE_METADATA,                     \
+                ofp11_instruction_write_metadata, false,    \
+                "write_metadata")                           \
+                                                            \
+    DEFINE_INST(OFPIT11_WRITE_ACTIONS,                      \
+                ofp11_instruction_actions,        true,     \
+                "write_actions")                            \
+                                                            \
+    DEFINE_INST(OFPIT11_APPLY_ACTIONS,                      \
+                ofp11_instruction_actions,        true,     \
+                "apply_actions")                            \
+                                                            \
+    DEFINE_INST(OFPIT11_CLEAR_ACTIONS,                      \
+                ofp11_instruction,                false,    \
+                "clear_actions")
+
+enum ovs_instruction_type {
+#define DEFINE_INST(ENUM, STRUCT, NAME, EXTENSIBLE) OVSINST_##ENUM,
+    OVS_INSTRUCTIONS
+#undef DEFINE_INST
+};
+
+enum {
+#define DEFINE_INST(ENUM, STRUCT, NAME, EXTENSIBLE) + 1
+    N_OVS_INSTRUCTIONS = OVS_INSTRUCTIONS
+#undef DEFINE_INST
+};
+
+static inline struct ofp11_instruction *
+instruction_next(const struct ofp11_instruction *inst)
+{
+    return ((struct ofp11_instruction *) (void *)
+            ((uint8_t *) inst + ntohs(inst->len)));
+}
+
+static inline bool
+instruction_is_valid(const struct ofp11_instruction *inst,
+                     size_t n_instructions)
+{
+    uint16_t len = ntohs(inst->len);
+    return (!(len % OFP11_INSTRUCTION_ALIGN)
+            && len >= sizeof *inst
+            && len / sizeof *inst <= n_instructions);
+}
+
+/* This macro is careful to check for instructions with bad lengths. */
+#define INSTRUCTION_FOR_EACH(ITER, LEFT, INSTRUCTIONS, N_INSTRUCTIONS)  \
+    for ((ITER) = (INSTRUCTIONS), (LEFT) = (N_INSTRUCTIONS);            \
+         (LEFT) > 0 && instruction_is_valid(ITER, LEFT);                \
+         ((LEFT) -= (ntohs((ITER)->len)                                 \
+                     / sizeof(struct ofp11_instruction)),               \
+          (ITER) = instruction_next(ITER)))
+
+static enum ofperr
+decode_openflow11_instruction(const struct ofp11_instruction *inst,
+                              enum ovs_instruction_type *type)
+{
+    uint16_t len = ntohs(inst->len);
+
+    switch (inst->type) {
+    case CONSTANT_HTONS(OFPIT11_EXPERIMENTER):
+        return OFPERR_OFPBIC_BAD_EXPERIMENTER;
+
+#define DEFINE_INST(ENUM, STRUCT, NAME, EXTENSIBLE)     \
+        case CONSTANT_HTONS(ENUM):                      \
+            if (EXTENSIBLE                              \
+                ? len >= sizeof(struct STRUCT)          \
+                : len == sizeof(struct STRUCT)) {       \
+                *type = OVSINST_##ENUM;                 \
+                return 0;                               \
+            } else {                                    \
+                return OFPERR_OFPBAC_BAD_LEN;           \
+            }
+OVS_INSTRUCTIONS
+#undef DEFINE_INST
+
+    default:
+        return OFPERR_OFPBIC_UNKNOWN_INST;
+    }
+}
+
+static enum ofperr
+decode_openflow11_instructions(const struct ofp11_instruction insts[],
+                               size_t n_insts,
+                               const struct ofp11_instruction *out[])
+{
+    const struct ofp11_instruction *inst;
+    size_t left;
+
+    memset(out, 0, N_OVS_INSTRUCTIONS * sizeof *out);
+    INSTRUCTION_FOR_EACH (inst, left, insts, n_insts) {
+        enum ovs_instruction_type type;
+        enum ofperr error;
+
+        error = decode_openflow11_instruction(inst, &type);
+        if (error) {
+            return error;
+        }
+
+        if (out[type]) {
+            return OFPERR_NXBIC_DUP_TYPE;
+        }
+        out[type] = inst;
+    }
+
+    if (left) {
+        VLOG_WARN_RL(&rl, "bad instruction format at offset %zu",
+                     (n_insts - left) * sizeof *inst);
+        return OFPERR_OFPBIC_BAD_LEN;
+    }
+    return 0;
+}
+
+static void
+get_actions_from_instruction(const struct ofp11_instruction *inst,
+                         const union ofp_action **actions,
+                         size_t *n_actions)
+{
+    *actions = (const union ofp_action *) (inst + 1);
+    *n_actions = (ntohs(inst->len) - sizeof *inst) / OFP11_INSTRUCTION_ALIGN;
+}
+
+enum ofperr
+ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
+                                     unsigned int instructions_len,
+                                     struct ofpbuf *ofpacts)
+{
+    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+    const struct ofp11_instruction *instructions;
+    const struct ofp11_instruction *insts[N_OVS_INSTRUCTIONS];
+    enum ofperr error;
+
+    ofpbuf_clear(ofpacts);
+
+    if (instructions_len % OFP11_INSTRUCTION_ALIGN != 0) {
+        VLOG_WARN_RL(&rl, "OpenFlow message instructions length %u is not a "
+                     "multiple of %d",
+                     instructions_len, OFP11_INSTRUCTION_ALIGN);
+        error = OFPERR_OFPBRC_BAD_LEN;
+        goto exit;
+    }
+
+    instructions = ofpbuf_try_pull(openflow, instructions_len);
+    if (instructions == NULL) {
+        VLOG_WARN_RL(&rl, "OpenFlow message instructions length %u exceeds "
+                     "remaining message length (%zu)",
+                     instructions_len, openflow->size);
+        error = OFPERR_OFPBRC_BAD_LEN;
+        goto exit;
+    }
+
+    error = decode_openflow11_instructions(
+        instructions, instructions_len / OFP11_INSTRUCTION_ALIGN,
+        insts);
+    if (error) {
+        goto exit;
+    }
+
+    if (insts[OVSINST_OFPIT11_APPLY_ACTIONS]) {
+        const union ofp_action *actions;
+        size_t n_actions;
+
+        get_actions_from_instruction(insts[OVSINST_OFPIT11_APPLY_ACTIONS],
+                                     &actions, &n_actions);
+        error = ofpacts_from_openflow11(actions, n_actions, ofpacts);
+        if (error) {
+            goto exit;
+        }
+    }
+
+    ofpact_put_END(ofpacts);
+
+    if (insts[OVSINST_OFPIT11_GOTO_TABLE] ||
+        insts[OVSINST_OFPIT11_WRITE_METADATA] ||
+        insts[OVSINST_OFPIT11_WRITE_ACTIONS] ||
+        insts[OVSINST_OFPIT11_CLEAR_ACTIONS]) {
+        error = OFPERR_OFPBIC_UNSUP_INST;
+        goto exit;
+    }
+
+exit:
     if (error) {
         ofpbuf_clear(ofpacts);
     }
@@ -574,7 +979,7 @@ static void
 ofpact_output_to_openflow10(const struct ofpact_output *output,
                             struct ofpbuf *out)
 {
-    struct ofp_action_output *oao;
+    struct ofp10_action_output *oao;
 
     oao = ofputil_put_OFPAT10_OUTPUT(out);
     oao->port = htons(output->port);
@@ -660,7 +1065,7 @@ ofpact_controller_to_openflow10(const struct ofpact_controller *oc,
                                 struct ofpbuf *out)
 {
     if (oc->controller_id == 0 && oc->reason == OFPR_ACTION) {
-        struct ofp_action_output *oao;
+        struct ofp10_action_output *oao;
 
         oao = ofputil_put_OFPAT10_OUTPUT(out);
         oao->port = htons(OFPP_CONTROLLER);
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index 7db01a5..6b86e25 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -379,9 +379,12 @@ struct ofpact_note {
 };
 
 /* Converting OpenFlow to ofpacts. */
-enum ofperr ofpacts_pull_openflow(struct ofpbuf *openflow,
-                                  unsigned int actions_len,
-                                  struct ofpbuf *ofpacts);
+enum ofperr ofpacts_pull_openflow10(struct ofpbuf *openflow,
+                                    unsigned int actions_len,
+                                    struct ofpbuf *ofpacts);
+enum ofperr ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
+                                                 unsigned int instructions_len,
+                                                 struct ofpbuf *ofpacts);
 enum ofperr ofpacts_check(const struct ofpact[],
                           const struct flow *, int max_ports);
 
diff --git a/lib/ofp-errors.h b/lib/ofp-errors.h
index 5f908db..61cef41 100644
--- a/lib/ofp-errors.h
+++ b/lib/ofp-errors.h
@@ -193,7 +193,7 @@ enum ofperr {
 /* ## --------------------- ## */
 
     /* OF1.1+(3).  Error in instruction list. */
-    OFPERR_OFPET_BAD_INSTRUCTION,
+    OFPERR_OFPIT_BAD_INSTRUCTION,
 
     /* OF1.1+(3,0).  Unknown instruction. */
     OFPERR_OFPBIC_UNKNOWN_INST,
@@ -222,6 +222,9 @@ enum ofperr {
     /* OF1.2+(3,8).  Permissions error. */
     OFPERR_OFPBIC_EPERM,
 
+    /* NX1.1+(3,256).  Duplicate instruction type in set of instructions. */
+    OFPERR_NXBIC_DUP_TYPE,
+
 /* ## --------------- ## */
 /* ## OFPET_BAD_MATCH ## */
 /* ## --------------- ## */
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index ae70fb5..bd414eb 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -293,10 +293,12 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         NOT_REACHED();
 
     case OFPUTIL_OFPAT10_OUTPUT:
+    case OFPUTIL_OFPAT11_OUTPUT:
         parse_output(arg, ofpacts);
         break;
 
     case OFPUTIL_OFPAT10_SET_VLAN_VID:
+    case OFPUTIL_OFPAT11_SET_VLAN_VID:
         vid = str_to_u32(arg);
         if (vid & ~VLAN_VID_MASK) {
             ovs_fatal(0, "%s: not a valid VLAN VID", arg);
@@ -305,6 +307,7 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         break;
 
     case OFPUTIL_OFPAT10_SET_VLAN_PCP:
+    case OFPUTIL_OFPAT11_SET_VLAN_PCP:
         pcp = str_to_u32(arg);
         if (pcp & ~7) {
             ovs_fatal(0, "%s: not a valid VLAN PCP", arg);
@@ -317,24 +320,29 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         break;
 
     case OFPUTIL_OFPAT10_SET_DL_SRC:
+    case OFPUTIL_OFPAT11_SET_DL_SRC:
         str_to_mac(arg, ofpact_put_SET_ETH_SRC(ofpacts)->mac);
         break;
 
     case OFPUTIL_OFPAT10_SET_DL_DST:
+    case OFPUTIL_OFPAT11_SET_DL_DST:
         str_to_mac(arg, ofpact_put_SET_ETH_DST(ofpacts)->mac);
         break;
 
     case OFPUTIL_OFPAT10_SET_NW_SRC:
+    case OFPUTIL_OFPAT11_SET_NW_SRC:
         str_to_ip(arg, &ip);
         ofpact_put_SET_IPV4_SRC(ofpacts)->ipv4 = ip;
         break;
 
     case OFPUTIL_OFPAT10_SET_NW_DST:
+    case OFPUTIL_OFPAT11_SET_NW_DST:
         str_to_ip(arg, &ip);
         ofpact_put_SET_IPV4_DST(ofpacts)->ipv4 = ip;
         break;
 
     case OFPUTIL_OFPAT10_SET_NW_TOS:
+    case OFPUTIL_OFPAT11_SET_NW_TOS:
         tos = str_to_u32(arg);
         if (tos & ~IP_DSCP_MASK) {
             ovs_fatal(0, "%s: not a valid TOS", arg);
@@ -343,10 +351,12 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         break;
 
     case OFPUTIL_OFPAT10_SET_TP_SRC:
+    case OFPUTIL_OFPAT11_SET_TP_SRC:
         ofpact_put_SET_L4_SRC_PORT(ofpacts)->port = str_to_u32(arg);
         break;
 
     case OFPUTIL_OFPAT10_SET_TP_DST:
+    case OFPUTIL_OFPAT11_SET_TP_DST:
         ofpact_put_SET_L4_DST_PORT(ofpacts)->port = str_to_u32(arg);
         break;
 
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 56c07a2..7577d17 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -1691,7 +1691,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
         ofputil_normalize_rule(&fm->cr);
 
         /* Now get the actions. */
-        error = ofpacts_pull_openflow(&b, b.size, ofpacts);
+        error = ofpacts_pull_openflow10(&b, b.size, ofpacts);
         if (error) {
             return error;
         }
@@ -1718,7 +1718,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
         if (error) {
             return error;
         }
-        error = ofpacts_pull_openflow(&b, b.size, ofpacts);
+        error = ofpacts_pull_openflow10(&b, b.size, ofpacts);
         if (error) {
             return error;
         }
@@ -2039,7 +2039,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
             return EINVAL;
         }
 
-        if (ofpacts_pull_openflow(msg, length - sizeof *ofs, ofpacts)) {
+        if (ofpacts_pull_openflow10(msg, length - sizeof *ofs, ofpacts)) {
             return EINVAL;
         }
 
@@ -2079,7 +2079,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
         }
 
         actions_len = length - sizeof *nfs - ROUND_UP(match_len, 8);
-        if (ofpacts_pull_openflow(msg, actions_len, ofpacts)) {
+        if (ofpacts_pull_openflow10(msg, actions_len, ofpacts)) {
             return EINVAL;
         }
 
@@ -2534,7 +2534,7 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po,
     ofpbuf_use_const(&b, opo, ntohs(opo->header.length));
     ofpbuf_pull(&b, sizeof *opo);
 
-    error = ofpacts_pull_openflow(&b, ntohs(opo->actions_len), ofpacts);
+    error = ofpacts_pull_openflow10(&b, ntohs(opo->actions_len), ofpacts);
     if (error) {
         return error;
     }
@@ -3655,7 +3655,8 @@ ofputil_action_code_from_name(const char *name)
 {
     static const char *names[OFPUTIL_N_ACTIONS] = {
         NULL,
-#define OFPAT10_ACTION(ENUM, STRUCT, NAME)             NAME,
+#define OFPAT10_ACTION(ENUM, STRUCT, NAME)           NAME,
+#define OFPAT11_ACTION(ENUM, STRUCT, NAME)           NAME,
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
 #include "ofp-util.def"
     };
@@ -3684,6 +3685,7 @@ ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf)
 
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME)                    \
     case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
+#define OFPAT11_ACTION OFPAT10_ACTION
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)        \
     case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
 #include "ofp-util.def"
@@ -3707,6 +3709,7 @@ ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf)
         ofputil_init_##ENUM(s);                                 \
         return s;                                               \
     }
+#define OFPAT11_ACTION OFPAT10_ACTION
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)            \
     void                                                        \
     ofputil_init_##ENUM(struct STRUCT *s)                       \
diff --git a/lib/ofp-util.def b/lib/ofp-util.def
index 8739ac0..974cd8f 100644
--- a/lib/ofp-util.def
+++ b/lib/ofp-util.def
@@ -3,7 +3,7 @@
 #ifndef OFPAT10_ACTION
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME)
 #endif
-OFPAT10_ACTION(OFPAT10_OUTPUT,       ofp_action_output,   "output")
+OFPAT10_ACTION(OFPAT10_OUTPUT,       ofp10_action_output, "output")
 OFPAT10_ACTION(OFPAT10_SET_VLAN_VID, ofp_action_vlan_vid, "mod_vlan_vid")
 OFPAT10_ACTION(OFPAT10_SET_VLAN_PCP, ofp_action_vlan_pcp, "mod_vlan_pcp")
 OFPAT10_ACTION(OFPAT10_STRIP_VLAN,   ofp_action_header,   "strip_vlan")
@@ -15,7 +15,26 @@ OFPAT10_ACTION(OFPAT10_SET_NW_TOS,   ofp_action_nw_tos,   "mod_nw_tos")
 OFPAT10_ACTION(OFPAT10_SET_TP_SRC,   ofp_action_tp_port,  "mod_tp_src")
 OFPAT10_ACTION(OFPAT10_SET_TP_DST,   ofp_action_tp_port,  "mod_tp_dst")
 OFPAT10_ACTION(OFPAT10_ENQUEUE,      ofp_action_enqueue,  "enqueue")
-#undef OFPAT10_ACTION
+
+#ifndef OFPAT11_ACTION
+#define OFPAT11_ACTION(ENUM, STRUCT, NAME)
+#endif
+OFPAT11_ACTION(OFPAT11_OUTPUT,       ofp11_action_output, "output")
+OFPAT11_ACTION(OFPAT11_SET_VLAN_VID, ofp_action_vlan_vid, "mod_vlan_vid")
+OFPAT11_ACTION(OFPAT11_SET_VLAN_PCP, ofp_action_vlan_pcp, "mod_vlan_pcp")
+OFPAT11_ACTION(OFPAT11_SET_DL_SRC,   ofp_action_dl_addr,  "mod_dl_src")
+OFPAT11_ACTION(OFPAT11_SET_DL_DST,   ofp_action_dl_addr,  "mod_dl_dst")
+OFPAT11_ACTION(OFPAT11_SET_NW_SRC,   ofp_action_nw_addr,  "mod_nw_src")
+OFPAT11_ACTION(OFPAT11_SET_NW_DST,   ofp_action_nw_addr,  "mod_nw_dst")
+OFPAT11_ACTION(OFPAT11_SET_NW_TOS,   ofp_action_nw_tos,   "mod_nw_tos")
+//OFPAT11_ACTION(OFPAT11_SET_NW_ECN,   ofp11_action_nw_ecn, "mod_nw_ecn")
+OFPAT11_ACTION(OFPAT11_SET_TP_SRC,   ofp_action_tp_port,  "mod_tp_src")
+OFPAT11_ACTION(OFPAT11_SET_TP_DST,   ofp_action_tp_port,  "mod_tp_dst")
+//OFPAT11_ACTION(OFPAT11_PUSH_VLAN,    ofp11_action_push,   "push_vlan")
+//OFPAT11_ACTION(OFPAT11_POP_VLAN,     ofp_action_header,   "pop_vlan")
+//OFPAT11_ACTION(OFPAT11_SET_QUEUE,    ofp11_action_set_queue, "set_queue")
+//OFPAT11_ACTION(OFPAT11_SET_NW_TTL,   ofp11_action_nw_ttl, "set_nw_ttl")
+//OFPAT11_ACTION(OFPAT11_DEC_NW_TTL,   ofp_action_header,   "dec_ttl")
 
 #ifndef NXAST_ACTION
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)
@@ -39,4 +58,7 @@ NXAST_ACTION(NXAST_EXIT,           nx_action_header,       0, "exit")
 NXAST_ACTION(NXAST_DEC_TTL,        nx_action_header,       0, "dec_ttl")
 NXAST_ACTION(NXAST_FIN_TIMEOUT,    nx_action_fin_timeout,  0, "fin_timeout")
 NXAST_ACTION(NXAST_CONTROLLER,     nx_action_controller,   0, "controller")
+
+#undef OFPAT10_ACTION
+#undef OFPAT11_ACTION
 #undef NXAST_ACTION
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 2dbde05..e154fa9 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -600,14 +600,16 @@ bool ofputil_frag_handling_from_string(const char *, enum ofp_config_flags *);
  */
 enum OVS_PACKED_ENUM ofputil_action_code {
     OFPUTIL_ACTION_INVALID,
-#define OFPAT10_ACTION(ENUM, STRUCT, NAME)             OFPUTIL_##ENUM,
+#define OFPAT10_ACTION(ENUM, STRUCT, NAME)           OFPUTIL_##ENUM,
+#define OFPAT11_ACTION(ENUM, STRUCT, NAME)           OFPUTIL_##ENUM,
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) OFPUTIL_##ENUM,
 #include "ofp-util.def"
 };
 
 /* The number of values of "enum ofputil_action_code". */
 enum {
-#define OFPAT10_ACTION(ENUM, STRUCT, NAME)             + 1
+#define OFPAT10_ACTION(ENUM, STRUCT, NAME)           + 1
+#define OFPAT11_ACTION(ENUM, STRUCT, NAME)           + 1
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) + 1
     OFPUTIL_N_ACTIONS = 1
 #include "ofp-util.def"
@@ -634,6 +636,9 @@ void *ofputil_put_action(enum ofputil_action_code, struct ofpbuf *buf);
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME)              \
     void ofputil_init_##ENUM(struct STRUCT *);          \
     struct STRUCT *ofputil_put_##ENUM(struct ofpbuf *);
+#define OFPAT11_ACTION(ENUM, STRUCT, NAME)              \
+    void ofputil_init_##ENUM(struct STRUCT *);          \
+    struct STRUCT *ofputil_put_##ENUM(struct ofpbuf *);
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)    \
     void ofputil_init_##ENUM(struct STRUCT *);          \
     struct STRUCT *ofputil_put_##ENUM(struct ofpbuf *);
diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
index 9a064a8..fe68c6d 100644
--- a/ofproto/connmgr.c
+++ b/ofproto/connmgr.c
@@ -1366,7 +1366,7 @@ schedule_packet_in(struct ofconn *ofconn, struct ofputil_packet_in pin)
         pin.send_len = pin.packet_len;
     } else {
         /* Caller should have initialized 'send_len' to 'max_len' specified in
-         * struct ofp_action_output. */
+         * output action. */
     }
     if (pin.buffer_id != UINT32_MAX) {
         pin.send_len = MIN(pin.send_len, ofconn->miss_send_len);
diff --git a/ofproto/in-band.c b/ofproto/in-band.c
index 2013869..c30f06b 100644
--- a/ofproto/in-band.c
+++ b/ofproto/in-band.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -411,11 +411,13 @@ in_band_run(struct in_band *ib)
 
     struct in_band_rule *rule, *next;
 
+    /* XXX Should use ofpacts here */
+
     memset(&actions, 0, sizeof actions);
-    actions.oa.output.type = htons(OFPAT10_OUTPUT);
-    actions.oa.output.len = htons(sizeof actions.oa);
-    actions.oa.output.port = htons(OFPP_NORMAL);
-    actions.oa.output.max_len = htons(0);
+    actions.oa.output10.type = htons(OFPAT10_OUTPUT);
+    actions.oa.output10.len = htons(sizeof actions.oa);
+    actions.oa.output10.port = htons(OFPP_NORMAL);
+    actions.oa.output10.max_len = htons(0);
     if (ib->queue_id < 0) {
         a = &actions.oa;
         na = sizeof actions.oa / sizeof(union ofp_action);
-- 
1.7.2.5




More information about the dev mailing list